Tipos conhecidos

O exemplo de KnownTypes demonstra como especificar informações sobre tipos derivados em um contrato de dados. Os contratos de dados permitem transmitir 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, os esquemas em vez dos tipos são comunicados e, portanto, o relacionamento entre os tipos não é preservado. O atributo KnownTypeAttribute 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 base é esperado.

Observação

O procedimento de instalação e as instruções de build desse exemplo estão 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 o DataMemberAttribute são aplicados à classe ComplexNumber 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 atributo KnownTypeAttribute no tipo ComplexNumber 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 tipo ComplexNumberWithMagnitude 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 forma que retorne um ComplexNumberWithMagnitude apenas para adição e subtração. (Mesmo que o contrato especifique ComplexNumber, isso é permitido devido ao atributo KnownTypeAttribute). A multiplicação e a divisão ainda retornam o tipo 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, tanto o contrato de serviço quanto o contrato de dados são definidos no arquivo de origem generateClient.cs, que é gerado pela Ferramenta de utilitário de metadados ServiceModel (Svcutil.exe) dos metadados do serviço. Como o atributo KnownTypeAttribute é especificado no contrato de dados do serviço, o cliente pode receber as classes ComplexNumber e ComplexNumberWithMagnitude ao usar o serviço. O cliente detecta 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 as 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. Verifique se você executou o Procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Para compilar a edição .NET do C# ou do Visual Basic da solução, siga as instruções contidas em Como Compilar as Amostras do Windows Communication Foundation.

  3. Para executar a amostra em uma configuração de computador único ou entre computadores, siga as instruções contidas em Como executar as amostras do Windows Communication Foundation.