Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Kelas KnownTypeAttribute memungkinkan Anda menentukan, terlebih dahulu, tipe yang harus disertakan untuk diproses selama deserialisasi. Untuk contoh kerja, lihat contoh Jenis yang Diketahui .
Biasanya, saat meneruskan parameter dan mengembalikan nilai antara klien dan layanan, kedua titik akhir berbagi semua kontrak data data yang akan dikirimkan. Namun, ini tidak terjadi dalam keadaan berikut:
Kontrak data yang dikirim didasarkan pada kontrak data yang diharapkan. Untuk informasi selengkapnya, lihat bagian tentang pewarisan dalam Kesepadanan Kontrak Data). Dalam hal ini, data yang dikirimkan tidak memiliki kontrak data yang sama seperti yang diharapkan oleh titik akhir penerimaan.
Jenis yang dideklarasikan untuk informasi yang akan ditransmisikan adalah antarmuka, dibandingkan dengan kelas, struktur, atau enumerasi. Oleh karena itu, tidak dapat diketahui terlebih dahulu jenis mana yang mengimplementasikan antarmuka yang benar-benar dikirim dan oleh karena itu, titik akhir penerimaan tidak dapat menentukan terlebih dahulu kontrak data untuk data yang dikirimkan.
Jenis yang dinyatakan untuk informasi yang akan ditransmisikan adalah Object. Karena setiap jenis mewarisi dari Object, dan tidak dapat diketahui terlebih dahulu jenis mana yang benar-benar dikirim, titik akhir penerimaan tidak dapat menentukan terlebih dahulu kontrak data untuk data yang dikirimkan. Ini adalah kasus khusus dari item pertama: Setiap kontrak data berasal dari bawaan, yaitu kontrak data kosong yang dihasilkan untuk Object.
Beberapa jenis, yang mencakup jenis .NET Framework, memiliki anggota yang berada di salah satu dari tiga kategori sebelumnya. Misalnya, Hashtable menggunakan Object untuk menyimpan objek aktual dalam tabel hash. Saat menserialisasikan jenis ini, sisi penerimaan tidak dapat menentukan terlebih dahulu kontrak data untuk anggota ini.
Kelas KnownTypeAttribute
Ketika data tiba di titik akhir penerimaan, runtime WCF mencoba mendeserialisasi data ke dalam instans jenis runtime bahasa umum (CLR). Jenis yang diinstansiasi untuk deserialisasi dipilih dengan terlebih dahulu memeriksa pesan yang diterima untuk menentukan kontrak data yang sesuai dengan isi pesan tersebut. Mesin deserialisasi kemudian mencoba menemukan jenis CLR yang mengimplementasikan kontrak data yang kompatibel dengan konten pesan. Kumpulan jenis kandidat yang diizinkan mesin deserialisasi selama proses ini disebut sebagai "kumpulan jenis yang diketahui" dari deserializer.
Salah satu cara untuk memberi tahu mesin deserialisasi tentang jenis adalah dengan menggunakan KnownTypeAttribute. Atribut tidak dapat diterapkan ke masing-masing anggota data, hanya untuk seluruh jenis kontrak data. Atribut diterapkan ke jenis luar yang dapat menjadi kelas atau struktur. Dalam penggunaannya yang paling dasar, menerapkan atribut menentukan tipe sebagai "tipe yang dikenal." Ini menyebabkan tipe tersebut menjadi bagian dari kumpulan tipe yang dikenal setiap kali objek dari tipe ini atau objek lain yang dirujuk melalui anggotanya sedang dideserialisasi. Lebih dari satu KnownTypeAttribute atribut dapat diterapkan ke jenis yang sama.
Jenis dan Primitif yang Diketahui
Jenis primitif, serta jenis tertentu yang diperlakukan sebagai primitif (misalnya, DateTime dan XmlElement) selalu "dikenal" dan tidak perlu ditambahkan melalui mekanisme ini. Tetapi, array tipe primitif harus ditambahkan secara eksplisit. Sebagian besar koleksi dianggap setara dengan struktur data array. (Koleksi non-generik dianggap setara dengan array Object). Untuk contoh penggunaan primitif, array primitif, dan koleksi primitif, lihat Contoh 4.
Nota
Tidak seperti jenis primitif lainnya, DateTimeOffset struktur bukan jenis yang diketahui secara default, sehingga harus ditambahkan secara manual ke daftar jenis yang diketahui.
Contoh
Contoh berikut menunjukkan penggunaan kelas KnownTypeAttribute.
Contoh 1
Ada tiga kelas dengan hubungan pewarisan.
[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
Kelas berikut CompanyLogo
dapat diserialisasi, tetapi tidak dapat diserialisasi jika anggota ShapeOfLogo
diatur ke objek CircleType
atau TriangleType
, karena mesin pembongkaran tidak mengenali jenis dengan nama kontrak data "Lingkaran" atau "Segitiga."
[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
Cara yang benar untuk menulis CompanyLogo
jenis diperlihatkan dalam kode berikut.
[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
Setiap kali tipe CompanyLogo2
eksternal sedang dideserialisasi, mesin deserialisasi tahu tentang CircleType
dan TriangleType
dan, sehingga dapat menemukan jenis yang cocok untuk kontrak data "Lingkaran" dan "Segitiga".
Contoh 2
Dalam contoh berikut, meskipun baik CustomerTypeA
maupun CustomerTypeB
memiliki kontrak data Customer
, sebuah instans CustomerTypeB
dibuat setiap kali PurchaseOrder
dideserialisasi, karena hanya CustomerTypeB
yang diketahui oleh mesin deserialisasi.
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
Contoh 3
Dalam contoh berikut, Hashtable menyimpan kontennya secara internal sebagai Object. Agar berhasil mendeserialisasi tabel hash, mesin deserialisasi harus mengetahui serangkaian tipe yang mungkin ada di dalamnya. Dalam hal ini, kita tahu terlebih dahulu bahwa hanya Book
dan Magazine
objek disimpan di Catalog
, sehingga ditambahkan menggunakan KnownTypeAttribute atribut .
[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
Contoh 4
Dalam contoh berikut, kontrak data menyimpan angka dan operasi untuk dilakukan pada angka tersebut. Anggota Numbers
data dapat berupa bilangan bulat, array bilangan bulat, atau List<T> yang berisi bilangan bulat.
Perhatian
Ini hanya akan berfungsi di sisi klien jika SVCUTIL.EXE digunakan untuk menghasilkan proksi WCF. SVCUTIL.EXE mengambil metadata dari layanan termasuk tipe yang sudah dikenal. Tanpa informasi ini, klien tidak akan dapat mendeserialisasi tipe data.
[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
Ini adalah kode aplikasi.
// 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
Jenis, Pewarisan, dan Antarmuka yang Diketahui
Ketika jenis yang diketahui dikaitkan dengan jenis tertentu menggunakan KnownTypeAttribute
atribut , jenis yang diketahui juga dikaitkan dengan semua jenis turunan dari jenis tersebut. Misalnya, lihat kode berikut.
[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
Kelas DoubleDrawing
tidak memerlukan KnownTypeAttribute
atribut untuk digunakan Square
dan Circle
di AdditionalShape
bidang , karena kelas dasar (Drawing
) sudah menerapkan atribut ini.
Jenis yang diketahui hanya dapat dikaitkan dengan kelas dan struktur, bukan antarmuka.
Jenis yang Diketahui Menggunakan Metode Generik Terbuka
Mungkin perlu menambahkan jenis generik sebagai jenis yang diketahui. Namun, jenis generik terbuka tidak dapat diteruskan sebagai parameter ke KnownTypeAttribute
atribut .
Masalah ini dapat diselesaikan dengan menggunakan mekanisme alternatif: Tulis metode yang mengembalikan daftar jenis untuk ditambahkan ke koleksi jenis yang diketahui. Nama metode kemudian ditentukan sebagai argumen string ke KnownTypeAttribute
atribut karena beberapa batasan.
Metode harus ada pada jenis yang KnownTypeAttribute
atributnya diterapkan, harus statis, tidak boleh menerima parameter, dan harus mengembalikan objek yang dapat ditetapkan ke IEnumerable dari Type.
Anda tidak dapat menggabungkan atribut KnownTypeAttribute
dengan nama metode dan atribut KnownTypeAttribute
dengan tipe konkret pada tipe yang sama. Selain itu, Anda tidak dapat menerapkan lebih dari satu KnownTypeAttribute
dengan nama metode yang sama ke tipe yang sama.
Lihat kelas berikut.
[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
Bidang theDrawing
berisi instans kelas generik ColorDrawing
dan BlackAndWhiteDrawing
, yang keduanya merupakan turunan dari kelas generik Drawing
. Biasanya, keduanya harus ditambahkan ke jenis yang diketahui, tetapi berikut ini bukan sintaks yang valid untuk atribut.
// 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)))>
Dengan demikian, metode harus dibuat untuk mengembalikan jenis ini. Cara yang benar untuk menulis jenis ini, kemudian, ditunjukkan dalam kode berikut.
[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
Cara Tambahan untuk Menambahkan Jenis yang Diketahui
Selain itu, jenis yang diketahui dapat ditambahkan melalui file konfigurasi. Ini berguna ketika Anda tidak mengendalikan tipe yang memerlukan tipe yang dikenal untuk deserialisasi yang tepat, seperti saat menggunakan pustaka tipe pihak ketiga dengan Windows Communication Foundation (WCF).
File konfigurasi berikut menunjukkan cara menentukan jenis yang diketahui dalam file konfigurasi.
<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>
Dalam file konfigurasi sebelumnya, jenis kontrak data yang disebut MyCompany.Library.Shape
dinyatakan memiliki MyCompany.Library.Circle
sebagai jenis yang diketahui.
Lihat juga
- KnownTypeAttribute
- Hashtable
- Object
- DataContractSerializer
- KnownTypes
- Jenis yang Diketahui
- Ekuivalensi Kontrak Data
- Merancang Kontrak Layanan