Veri Sözleşmesi Bilinen Türler

KnownTypeAttribute sınıfı, seri durumdan çıkarma sırasında dikkate alınması gereken türleri önceden belirtmenize olanak tanır. Çalışan bir örnek için Bilinen Türler örneğine bakın.

Normalde, bir istemci ile hizmet arasında parametre ve dönüş değerleri geçirirken, her iki uç nokta da iletilecek verilerin tüm veri sözleşmelerini paylaşır. Ancak, aşağıdaki durumlarda böyle bir durum söz konusu değildir:

  • Gönderilen veri sözleşmesi beklenen veri sözleşmesinden türetilir. Daha fazla bilgi için Veri Sözleşmesi Eşdeğerliği'nde devralma hakkındaki bölüme bakın. Bu durumda, iletilen veriler, alıcı uç nokta tarafından beklenenle aynı veri sözleşmesine sahip değildir.

  • İletilecek bilgilerin bildirilen türü, bir sınıf, yapı veya numaralandırmanın aksine bir arabirimdir. Bu nedenle, arabirimi uygulayan türün aslında gönderildiği önceden bilinmez ve bu nedenle, alıcı uç nokta iletilen veriler için veri sözleşmesini önceden belirleyemez.

  • İletilecek bilgiler için bildirilen tür: Object. Her tür öğesinden Objectdevralındığından ve gerçekte hangi türün gönderildiği önceden bilinemediğinden, alıcı uç nokta iletilen veriler için veri sözleşmesini önceden belirleyemez. Bu, ilk öğenin özel bir durumudur: Her veri sözleşmesi, için Objectoluşturulan boş bir veri sözleşmesi olan varsayılandan türetilir.

  • .NET Framework türlerini içeren bazı türlerin, önceki üç kategoriden birinde yer alan üyeleri vardır. Örneğin, Hashtable karma tablosunda gerçek nesneleri depolamak için kullanır Object . Bu türleri seri hale getirdiğinizde, alıcı taraf bu üyeler için veri sözleşmesini önceden belirleyemez.

KnownTypeAttribute Sınıfı

Veriler bir alıcı uç noktasına ulaştığında, WCF çalışma zamanı verileri ortak dil çalışma zamanı (CLR) türünün bir örneğine seri durumdan çıkarma girişiminde bulunur. Seri durumdan çıkarma için örneği oluşturulan tür, önce gelen ileti incelenerek seçilir ve ileti içeriğinin uygun olduğu veri sözleşmesini belirler. Seri durumdan çıkarma altyapısı daha sonra ileti içeriğiyle uyumlu bir veri sözleşmesi uygulayan bir CLR türü bulmaya çalışır. Seri durumdan çıkarma altyapısının bu işlem sırasında izin verdiği aday türleri kümesi, seri durumdan çıkarıcının "bilinen türler" kümesi olarak adlandırılır.

Seri durumdan çıkarma altyapısına bir tür hakkında bilgi vermenin bir yolu, kullanmaktır KnownTypeAttribute. Özniteliği tek tek veri üyelerine uygulanamaz, yalnızca veri sözleşmesi türlerinin tamamına uygulanamaz. özniteliği, bir sınıf veya yapı olabilecek bir dış türe uygulanır. En temel kullanımda özniteliğinin uygulanması bir türü "bilinen tür" olarak belirtir. Bu, dış türün veya üyeleri aracılığıyla başvuruda bulunılan herhangi bir nesnenin seri durumdan çıkarıldığı her durumda bilinen türün bilinen türler kümesinin bir parçası olmasına neden olur. Aynı türe birden KnownTypeAttribute fazla öznitelik uygulanabilir.

Bilinen Türler ve Temel Öğeler

İlkel türler ve ilkel olarak ele alınan bazı türler (örneğin, DateTime ve XmlElement) her zaman "bilinir" ve bu mekanizma aracılığıyla hiçbir zaman eklenmesi gerekmez. Ancak, ilkel tür dizilerinin açıkça eklenmesi gerekir. Koleksiyonların çoğu dizilerle eşdeğer olarak kabul edilir. (Genel olmayan koleksiyonlar, dizilerine Objecteşdeğer olarak kabul edilir). İlkelleri, ilkel dizileri ve ilkel koleksiyonları kullanma örneği için bkz. Örnek 4.

Not

Diğer ilkel türlerin DateTimeOffset aksine, yapı varsayılan olarak bilinen bir tür değildir, bu nedenle bilinen türler listesine el ile eklenmelidir.

Örnekler

Aşağıdaki örneklerde kullanılan sınıf gösterilmektedir KnownTypeAttribute .

Örnek 1

Devralma ilişkisi olan üç sınıf vardır.

[DataContract]
public class Shape { }

[DataContract(Name = "Circle")]
public class CircleType : Shape { }

[DataContract(Name = "Triangle")]
public class TriangleType : Shape { }
<DataContract()> _
Public Class Shape
End Class

<DataContract(Name:="Circle")> _
Public Class CircleType
    Inherits Shape
End Class
<DataContract(Name:="Triangle")> _
Public Class TriangleType
    Inherits Shape
End Class

Aşağıdaki CompanyLogo sınıf seri hale getirilebilir, ancak seri durumdan ShapeOfLogo çıkarma altyapısı "Circle" veya "Triangle" veri sözleşmesi adlarına sahip herhangi bir türü tanımadığından, üye bir CircleType veya nesnesine TriangleType ayarlanırsa seri durumdan çıkarılamaz.

[DataContract]
public class CompanyLogo
{
    [DataMember]
    private Shape ShapeOfLogo;
    [DataMember]
    private int ColorOfLogo;
}
<DataContract()> _
Public Class CompanyLogo
    <DataMember()> _
    Private ShapeOfLogo As Shape
    <DataMember()> _
    Private ColorOfLogo As Integer
End Class

Türü yazmanın CompanyLogo doğru yolu aşağıdaki kodda gösterilmiştir.

[DataContract]
[KnownType(typeof(CircleType))]
[KnownType(typeof(TriangleType))]
public class CompanyLogo2
{
    [DataMember]
    private Shape ShapeOfLogo;
    [DataMember]
    private int ColorOfLogo;
}
<DataContract(), KnownType(GetType(CircleType)), KnownType(GetType(TriangleType))> _
Public Class CompanyLogo2
    <DataMember()> _
    Private ShapeOfLogo As Shape
    <DataMember()> _
    Private ColorOfLogo As Integer
End Class

Dış tür CompanyLogo2 seri durumdan çıkarılırken seri durumdan çıkarma altyapısı ve TriangleType hakkında bilgi edinir CircleType ve bu nedenle "Circle" ve "Triangle" veri sözleşmeleri için eşleşen türleri bulabilir.

Örnek 2

Aşağıdaki örnekte, hem hem de CustomerTypeACustomerTypeB veri sözleşmesine Customer sahip olsa da, CustomerTypeB seri durumdan çıkarma altyapısı yalnızca CustomerTypeB bilindiğinden, seri durumdan çıkarıldığı her durumda PurchaseOrder örneği oluşturulur.

public interface ICustomerInfo
{
    string ReturnCustomerName();
}

[DataContract(Name = "Customer")]
public class CustomerTypeA : ICustomerInfo
{
    public string ReturnCustomerName()
    {
        return "no name";
    }
}

[DataContract(Name = "Customer")]
public class CustomerTypeB : ICustomerInfo
{
    public string ReturnCustomerName()
    {
        return "no name";
    }
}

[DataContract]
[KnownType(typeof(CustomerTypeB))]
public class PurchaseOrder
{
    [DataMember]
    ICustomerInfo buyer;

    [DataMember]
    int amount;
}
Public Interface ICustomerInfo
    Function ReturnCustomerName() As String
End Interface

<DataContract(Name:="Customer")> _
Public Class CustomerTypeA
    Implements ICustomerInfo
    Public Function ReturnCustomerName() _
    As String Implements ICustomerInfo.ReturnCustomerName
        Return "no name"
    End Function
End Class

<DataContract(Name:="Customer")> _
Public Class CustomerTypeB
    Implements ICustomerInfo
    Public Function ReturnCustomerName() _
    As String Implements ICustomerInfo.ReturnCustomerName
        Return "no name"
    End Function
End Class

<DataContract(), KnownType(GetType(CustomerTypeB))> _
Public Class PurchaseOrder
    <DataMember()> _
    Private buyer As ICustomerInfo

    <DataMember()> _
    Private amount As Integer
End Class

Örnek 3

Aşağıdaki örnekte, bir Hashtable içindekileri olarak Objectdepolar. Bir karma tablosunun seri durumdan başarıyla çıkarılabilmesi için seri durumdan çıkarma altyapısının orada oluşabilecek olası türler kümesini bilmesi gerekir. Bu durumda, yalnızca Book ve Magazine nesnelerinin içinde Catalogdepolandığını önceden biliyoruz, bu nedenle bunlar özniteliği kullanılarak KnownTypeAttribute eklenir.

[DataContract]
public class Book { }

[DataContract]
public class Magazine { }

[DataContract]
[KnownType(typeof(Book))]
[KnownType(typeof(Magazine))]
public class LibraryCatalog
{
    [DataMember]
    System.Collections.Hashtable theCatalog;
}
<DataContract()> _
Public Class Book
End Class

<DataContract()> _
Public Class Magazine
End Class

<DataContract(), KnownType(GetType(Book)), KnownType(GetType(Magazine))> _
Public Class LibraryCatalog
    <DataMember()> _
    Private theCatalog As System.Collections.Hashtable
End Class

Örnek 4

Aşağıdaki örnekte, veri sözleşmesi sayı üzerinde gerçekleştirilecek bir sayıyı ve işlemi depolar. Veri Numbers üyesi bir tamsayı, tamsayı dizisi veya tamsayı içeren bir List<T> dizi olabilir.

Dikkat

Bu yalnızca bir WCF ara sunucusu oluşturmak için SVCUTIL.EXE kullanılırsa istemci tarafında çalışır. SVCUTIL.EXE bilinen türler dahil olmak üzere hizmetten meta verileri alır. Bu bilgiler olmadan istemci türleri seri durumdan çıkaramaz.

[DataContract]
[KnownType(typeof(int[]))]
public class MathOperationData
{
    private object numberValue;
    [DataMember]
    public object Numbers
    {
        get { return numberValue; }
        set { numberValue = value; }
    }
    //[DataMember]
    //public Operation Operation;
}
<DataContract(), KnownType(GetType(Integer()))> _
Public Class MathOperationData
    Private numberValue As Object

    <DataMember()> _
    Public Property Numbers() As Object
        Get
            Return numberValue
        End Get
        Set(ByVal value As Object)
            numberValue = value
        End Set
    End Property
End Class

Bu, uygulama kodudur.

// This is in the service application code:
static void Run()
{

    MathOperationData md = new MathOperationData();

    // This will serialize and deserialize successfully because primitive
    // types like int are always known.
    int a = 100;
    md.Numbers = a;

    // This will serialize and deserialize successfully because the array of
    // integers was added to known types.
    int[] b = new int[100];
    md.Numbers = b;

    // This will serialize and deserialize successfully because the generic
    // List<int> is equivalent to int[], which was added to known types.
    List<int> c = new List<int>();
    md.Numbers = c;
    // This will serialize but will not deserialize successfully because
    // ArrayList is a non-generic collection, which is equivalent to
    // an array of type object. To make it succeed, object[]
    // must be added to the known types.
    ArrayList d = new ArrayList();
    md.Numbers = d;
}
' This is in the service application code:
Shared Sub Run()
    Dim md As New MathOperationData()
    ' This will serialize and deserialize successfully because primitive 
    ' types like int are always known.
    Dim a As Integer = 100
    md.Numbers = a

    ' This will serialize and deserialize successfully because the array of 
    ' integers was added to known types.
    Dim b(99) As Integer
    md.Numbers = b

    ' This will serialize and deserialize successfully because the generic 
    ' List(Of Integer) is equivalent to Integer(), which was added to known types.
    Dim c As List(Of Integer) = New List(Of Integer)()
    md.Numbers = c
    ' This will serialize but will not deserialize successfully because 
    ' ArrayList is a non-generic collection, which is equivalent to 
    ' an array of type object. To make it succeed, object[]
    ' must be added to the known types.
    Dim d As New ArrayList()
    md.Numbers = d

End Sub

Bilinen Türler, Devralma ve Arabirimler

Bilinen bir tür özniteliği kullanılarak KnownTypeAttribute belirli bir türle ilişkilendirildiğinde, bilinen tür de bu türün türetilmiş tüm türleriyle ilişkilendirilir. Örneğin, aşağıdaki koda bakın.

[DataContract]
[KnownType(typeof(Square))]
[KnownType(typeof(Circle))]
public class MyDrawing
{
    [DataMember]
    private object Shape;
    [DataMember]
    private int Color;
}

[DataContract]
public class DoubleDrawing : MyDrawing
{
    [DataMember]
    private object additionalShape;
}
<DataContract(), KnownType(GetType(Square)), KnownType(GetType(Circle))> _
Public Class MyDrawing
    <DataMember()> _
    Private Shape As Object
    <DataMember()> _
    Private Color As Integer
End Class

<DataContract()> _
Public Class DoubleDrawing
    Inherits MyDrawing
    <DataMember()> _
    Private additionalShape As Object
End Class

DoubleDrawing Temel sınıfta (Drawing) bu öznitelikler zaten uygulandığından, sınıfın ve CircleAdditionalShape alanında kullanılması Square gerekmezKnownTypeAttribute.

Bilinen türler arabirimlerle değil yalnızca sınıflarla ve yapılarla ilişkilendirilebilir.

Açık Genel Yöntemler Kullanan Bilinen Türler

Bilinen bir tür olarak genel bir tür eklemek gerekebilir. Ancak, açık bir genel tür özniteliğine KnownTypeAttribute parametre olarak geçirilemez.

Bu sorun alternatif bir mekanizma kullanılarak çözülebilir: Bilinen türler koleksiyonuna eklenecek türlerin listesini döndüren bir yöntem yazın. Ardından yöntemin adı, bazı kısıtlamalar nedeniyle özniteliğin KnownTypeAttribute dize bağımsız değişkeni olarak belirtilir.

yöntemi, özniteliğin uygulandığı türde KnownTypeAttribute bulunmalıdır, statik olmalıdır, parametre kabul etmemelidir ve öğesine atanabilecek IEnumerableTypebir nesne döndürmelidir.

özniteliğini KnownTypeAttribute bir yöntem adıyla ve KnownTypeAttribute öznitelikleri aynı türdeki gerçek türlerle birleştiremezsiniz. Ayrıca, aynı türe yöntem adıyla birden KnownTypeAttribute fazla uygulayamazsınız.

Aşağıdaki sınıfa bakın.

[DataContract]
public class DrawingRecord<T>
{
    [DataMember]
    private T theData;
    [DataMember]
    private GenericDrawing<T> theDrawing;
}
<DataContract()> _
Public Class DrawingRecord(Of T)
    <DataMember()> _
    Private theData As T
    <DataMember()> _
    Private theDrawing As GenericDrawing(Of T)
End Class

alanı, theDrawing her ikisi de genel sınıfından devralan genel bir sınıfın ColorDrawingBlackAndWhiteDrawingve genel sınıfın Drawingörneklerini içerir. Normalde, her ikisi de bilinen türlere eklenmelidir, ancak öznitelikler için aşağıdaki geçerli bir söz dizimi değildir.

// Invalid syntax for attributes:  
// [KnownType(typeof(ColorDrawing<T>))]  
// [KnownType(typeof(BlackAndWhiteDrawing<T>))]  
' Invalid syntax for attributes:  
' <KnownType(GetType(ColorDrawing(Of T))), _  
' KnownType(GetType(BlackAndWhiteDrawing(Of T)))>  

Bu nedenle, bu türleri döndürmek için bir yöntem oluşturulmalıdır. Bu tür yazmanın doğru yolu aşağıdaki kodda gösterilmiştir.

[DataContract]
[KnownType("GetKnownType")]
public class DrawingRecord2<T>
{
    [DataMember]
    private T TheData;
    [DataMember]
    private GenericDrawing<T> TheDrawing;

    private static Type[] GetKnownType()
    {
        Type[] t = new Type[2];
        t[0] = typeof(ColorDrawing<T>);
        t[1] = typeof(BlackAndWhiteDrawing<T>);
        return t;
    }
}
<DataContract(), KnownType("GetKnownType")> _
Public Class DrawingRecord2(Of T)
    Private TheData As T
    Private TheDrawing As GenericDrawing(Of T)

    Private Shared Function GetKnownType() As Type()
        Dim t(1) As Type
        t(0) = GetType(ColorDrawing(Of T))
        t(1) = GetType(BlackAndWhiteDrawing(Of T))
        Return t
    End Function
End Class

Bilinen Türleri Eklemenin Ek Yolları

Ayrıca, bilinen türler bir yapılandırma dosyası aracılığıyla eklenebilir. Bu, Windows Communication Foundation (WCF) ile üçüncü taraf tür kitaplıklarını kullanırken olduğu gibi düzgün seri durumdan çıkarma için bilinen türleri gerektiren türü denetlemediğinizde kullanışlıdır.

Aşağıdaki yapılandırma dosyası, yapılandırma dosyasında bilinen bir türün nasıl belirtileceğini gösterir.

<configuration>

<system.runtime.serialization>

<dataContractSerializer>

<declaredTypes>

<add type="MyCompany.Library.Shape,

MyAssembly, Version=2.0.0.0, Culture=neutral,

PublicKeyToken=XXXXXX, processorArchitecture=MSIL">

<knownType type="MyCompany.Library.Circle,

MyAssembly, Version=2.0.0.0, Culture=neutral,

PublicKeyToken=XXXXXX, processorArchitecture=MSIL"/>

</add>

</declaredTypes>

</dataContractSerializer>

</system.runtime.serialization>

</configuration>

Önceki yapılandırma dosyasında adlı MyCompany.Library.Shape bir veri sözleşmesi türü, bilinen bir tür olarak bildirilir MyCompany.Library.Circle .

Ayrıca bkz.