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 CustomerTypeA
CustomerTypeB
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 Catalog
depolandığı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 Circle
AdditionalShape
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 ColorDrawing
BlackAndWhiteDrawing
ve 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
.