Partilhar via


Tipos conhecidos

O exemplo KnownTypes demonstra como especificar informações sobre tipos derivados em um contrato de dados. Os contratos de dados permitem que você passe dados estruturados de e para serviços. Na programação orientada a objetos, um tipo que herda de outro tipo pode ser usado no lugar do tipo original. Na programação orientada a serviços, esquemas em vez de tipos são comunicados e, portanto, a relação entre tipos não é preservada. O KnownTypeAttribute atributo permite que informações sobre tipos derivados sejam incluídas no contrato de dados. Se esse mecanismo não for usado, um tipo derivado não poderá ser enviado ou recebido onde um tipo de base é esperado.

Nota

O procedimento de configuração e as instruções de compilação para este exemplo estão localizados no final deste tópico.

O contrato de serviço para o serviço usa números complexos, conforme mostrado no código de exemplo a seguir.

// Define a service contract.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
    [OperationContract]
    ComplexNumber Add(ComplexNumber n1, ComplexNumber n2);
    [OperationContract]
    ComplexNumber Subtract(ComplexNumber n1, ComplexNumber n2);
    [OperationContract]
    ComplexNumber Multiply(ComplexNumber n1, ComplexNumber n2);
    [OperationContract]
    ComplexNumber Divide(ComplexNumber n1, ComplexNumber n2);
}

O DataContractAttribute e DataMemberAttribute é aplicado à ComplexNumber classe para indicar quais campos da classe podem ser passados entre o cliente e o serviço. A classe derivada ComplexNumberWithMagnitude pode ser usada no lugar de ComplexNumber. O KnownTypeAttribute atributo no ComplexNumber tipo indica isso.

[DataContract(Namespace="http://Microsoft.ServiceModel.Samples")]
[KnownType(typeof(ComplexNumberWithMagnitude))]
public class ComplexNumber
{
    [DataMember]
    public double Real = 0.0D;
    [DataMember]
    public double Imaginary = 0.0D;

    public ComplexNumber(double real, double imaginary)
    {
        this.Real = real;
        this.Imaginary = imaginary;
    }
}

O ComplexNumberWithMagnitude tipo deriva de ComplexNumber mas adiciona um membro de dados adicional, Magnitude.

[DataContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public class ComplexNumberWithMagnitude : ComplexNumber
{
    public ComplexNumberWithMagnitude(double real, double imaginary) :
        base(real, imaginary) { }

    [DataMember]
    public double Magnitude
    {
        get { return Math.Sqrt(Imaginary*Imaginary  + Real*Real); }
        set { throw new NotImplementedException(); }
    }
}

Para demonstrar o recurso de tipos conhecidos, o serviço é implementado de tal forma que retorna um ComplexNumberWithMagnitude apenas para adição e subtração. (Mesmo que o contrato especifique ComplexNumber, isso é permitido por causa do KnownTypeAttribute atributo). Multiplicação e divisão ainda retornam o tipo de base ComplexNumber .

public class DataContractCalculatorService : IDataContractCalculator
{
    public ComplexNumber Add(ComplexNumber n1, ComplexNumber n2)
    {
        //Return the derived type.
        return new ComplexNumberWithMagnitude(n1.Real + n2.Real,
                                      n1.Imaginary + n2.Imaginary);
    }

    public ComplexNumber Subtract(ComplexNumber n1, ComplexNumber n2)
    {
        //Return the derived type.
        return new ComplexNumberWithMagnitude(n1.Real - n2.Real,
                                 n1.Imaginary - n2.Imaginary);
    }

    public ComplexNumber Multiply(ComplexNumber n1, ComplexNumber n2)
    {
        double real1 = n1.Real * n2.Real;
        double imaginary1 = n1.Real * n2.Imaginary;
        double imaginary2 = n2.Real * n1.Imaginary;
        double real2 = n1.Imaginary * n2.Imaginary * -1;
        //Return the base type.
        return new ComplexNumber(real1 + real2, imaginary1 +
                                                  imaginary2);
    }

    public ComplexNumber Divide(ComplexNumber n1, ComplexNumber n2)
    {
        ComplexNumber conjugate = new ComplexNumber(n2.Real,
                                     -1*n2.Imaginary);
        ComplexNumber numerator = Multiply(n1, conjugate);
        ComplexNumber denominator = Multiply(n2, conjugate);
        //Return the base type.
        return new ComplexNumber(numerator.Real / denominator.Real,
                                             numerator.Imaginary);
    }
}

No cliente, o contrato de serviço e o contrato de dados são definidos no generatedClient.cs do arquivo de origem, que é gerado pela ferramenta ServiceModel Metadata Utility Tool (Svcutil.exe) a partir de metadados de serviço. Como o KnownTypeAttribute atributo é especificado no contrato de dados do serviço, o cliente pode receber as ComplexNumber classes e ComplexNumberWithMagnitude ao usar o serviço. O cliente deteta se obteve um ComplexNumberWithMagnitude e gera a saída apropriada:

// Create a client
DataContractCalculatorClient client =
    new DataContractCalculatorClient();

// Call the Add service operation.
ComplexNumber value1 = new ComplexNumber() { real = 1, imaginary = 2 };
ComplexNumber value2 = new ComplexNumber() { real = 3, imaginary = 4 };
ComplexNumber result = client.Add(value1, value2);
Console.WriteLine("Add({0} + {1}i, {2} + {3}i) = {4} + {5}i",
    value1.real, value1.imaginary, value2.real, value2.imaginary,
    result.real, result.imaginary);
if (result is ComplexNumberWithMagnitude)
{
    Console.WriteLine("Magnitude: {0}",
        ((ComplexNumberWithMagnitude)result).Magnitude);
}
else
{
    Console.WriteLine("No magnitude was sent from the service");
}

Quando você executa o exemplo, as solicitações e respostas da operação são exibidas na janela do console do cliente. Observe que uma magnitude é impressa para adição e subtração, mas não para multiplicação e divisão devido à forma como o serviço foi implementado. Pressione ENTER na janela do cliente para desligar o cliente.

Add(1 + 2i, 3 + 4i) = 4 + 6i
Magnitude: 7.21110255092798
Subtract(1 + 2i, 3 + 4i) = -2 + -2i
Magnitude: 2.82842712474619
Multiply(2 + 3i, 4 + 7i) = -13 + 26i
No magnitude was sent from the service
Divide(3 + 7i, 5 + -2i) = 0.0344827586206897 + 41i
No magnitude was sent from the service

    Press <ENTER> to terminate client.

Para configurar, compilar e executar o exemplo

  1. Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Para criar a edição C# ou Visual Basic .NET da solução, siga as instruções em Criando os exemplos do Windows Communication Foundation.

  3. Para executar o exemplo em uma configuração de máquina única ou cruzada, siga as instruções em Executando os exemplos do Windows Communication Foundation.