Aracılığıyla paylaş


Veri Sözleşmesi Bilinen Türleri

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 gerçek nesneleri karma tablosunda depolamak için Object kullanır. 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 serileştirme girişiminde bulunur. Seriden çıkarma için örneği oluşturulacak tür, önce gelen iletinin incelenmesi ve mesajın içeriğinin hangi veri sözleşmesine uygun olduğunun belirlenmesiyle seçilir. 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, KnownTypeAttribute kullanmaktır. Ö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 Primitifler

İ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.

Uyarı

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 üye bir ShapeOfLogo veya CircleType nesnesine ayarlanırsa, seri durumdan çıkarılamaz çünkü seri durumdan çıkarma altyapısı "Circle" veya "Triangle" veri sözleşmesi adlarına sahip herhangi bir türü tanımamaktadır.

[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 hale getirilirken, seri durumdan çıkarma altyapısı CircleType ve TriangleType hakkında bilgi sahibi olur 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 CustomerTypeA hem de CustomerTypeBCustomer veri sözleşmesine sahip olsa da, CustomerTypeB'nin seri duruma getirilmesi her gerçekleştiğinde bir PurchaseOrder örneği oluşturulur, çünkü seri durumdan çıkarma motoru yalnızca CustomerTypeB'i bilmektedir.

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çeriğini Object olarak dahili olarak depolar. Bir karma tablosunu başarıyla seri durumdan çıkarmak için serileştirme motorunun orada meydana gelebilecek 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 bir sayıyı ve bu sayı üzerinde gerçekleştirilecek bir 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 bilgiye sahip olmadan, istemci türleri deserilize edemez.

[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 sınıfı, KnownTypeAttribute ve SquareCircle alanında kullanmak için AdditionalShape özniteliğine ihtiyaç duymaz, çünkü temel sınıf (Drawing) bu özniteliklere zaten sahiptir.

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öntem, KnownTypeAttribute özniteliğinin uygulandığı türde bulunmalı, statik olmalı, parametre kabul etmemeli ve IEnumerable'nin Type'ine atanabilecek bir 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 ve ColorDrawing adında genel sınıf örnekleri içerir ve her ikisi de BlackAndWhiteDrawing adlı genel sınıfından devralınır. 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 MyCompany.Library.Shape adlı bir veri sözleşmesi türü, MyCompany.Library.Circle'yi bilinen bir tür olarak içerecek şekilde bildirilir.

Ayrıca bakınız