已知型別

KnownTypes 範例會示範如何在資料合約中指定有關衍生型別的資訊。 資料合約可以讓您在服務間來回傳遞結構化資料。 在物件導向程式設計中,繼承自另一個型別的型別可以用來取代原始型別。 在服務導向程式設計中,會使用結構描述而不是型別進行通訊,因此不會保留型別之間的關係。 KnownTypeAttribute 屬性可以讓關於衍生型別的資訊包含到資料合約中。 如果不使用這個機制,這時將無法傳送或接收衍生型別,因為預期是使用基底型別 (Base Type)。

注意

此範例的安裝程序與建置指示位於本主題的結尾。

此服務的服務合約會使用複數,如下列範例程式碼所示。

// 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);
}

DataContractAttributeDataMemberAttribute 會套用至 ComplexNumber 類別,以便指示可在用戶端與服務之間傳遞的類別欄位。 衍生的 ComplexNumberWithMagnitude 類別可以用來取代 ComplexNumberKnownTypeAttribute 型別的 ComplexNumber 屬性會指示這項資訊。

[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;
    }
}

ComplexNumberWithMagnitude 型別衍生自 ComplexNumber,但是其新增額外的資料成員,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(); }
    }
}

為了示範已知型別功能,此服務會實作成只傳回加法與減法的 ComplexNumberWithMagnitude。 (雖然合約會指定 ComplexNumber,但是因為 KnownTypeAttribute 屬性的關係,所以仍會允許這項行為)。 乘法與除法仍然會傳回基底 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);
    }
}

在用戶端上,服務合約與資料合約都會定義於 generatedClient.cs 原始程式檔中,而這個檔案是從服務中繼資料的 ServiceModel 中繼資料公用程式工具 (Svcutil.exe) 所產生的。 因為服務資料合約中是指定 KnownTypeAttribute 屬性,所以用戶端在使用服務時便能夠同時接收 ComplexNumberComplexNumberWithMagnitude 類別。 用戶端會偵測其是否收到 ComplexNumberWithMagnitude,然後產生適當的輸出:

// 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");
}

當您執行範例時,作業的要求和回應會顯示在用戶端主控台視窗中。 請注意,此服務的實作方式會使得加法與減法列印值範圍,但是乘法與除法則不會列印。 在用戶端視窗中按下 ENTER 鍵,即可關閉用戶端。

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.

若要安裝、建置及執行範例

  1. 確定您已執行 Windows Communication Foundation 範例的一次性安裝程序

  2. 若要建置方案的 C# 或 Visual Basic .NET 版本,請遵循 Building the Windows Communication Foundation Samples中的指示。

  3. 若要在單一或多部電腦組態中執行此範例,請遵循執行 Windows Communication Foundation 範例中的指示進行。