Share via


데이터 계약의 컬렉션 형식

컬렉션 은 특정 형식의 항목으로 구성된 목록입니다. .NET Framework의 경우 이러한 목록은 배열이나 여러 형식(제네릭 목록, 제네릭 BindingList<T>, StringCollection 또는 ArrayList)을 사용하여 나타낼 수 있습니다. 예를 들어, 컬렉션은 지정된 고객에 대한 주소 목록을 보유할 수 있습니다. 실제 형식에 관계없이 이러한 컬렉션을 목록 컬렉션이라고 합니다.

하나의 항목("키")과 다른 항목("값") 간의 연결을 나타내는 특별한 형태의 컬렉션이 있습니다. .NET Framework에서 해당 컬렉션은 Hashtable 및 제네릭 사전과 같은 형식으로 표시됩니다. 예를 들어, 연결 컬렉션은 도시("키")를 해당 도시의 인구("값")에 매핑할 수 있습니다. 실제 형식에 관계없이 이러한 컬렉션을 사전 컬렉션이라고 합니다.

데이터 계약 모델에서 컬렉션은 별도로 처리됩니다.

배열 및 제네릭 컬렉션을 비롯하여 IEnumerable 인터페이스를 구현하는 형식은 컬렉션으로 인식됩니다. 이 중에서 IDictionary 또는 제네릭 IDictionary<TKey,TValue> 인터페이스를 구현하는 형식은 사전 컬렉션이며, 다른 모든 형식은 목록 컬렉션입니다.

Add라는 메서드 및 매개 변수가 없는 생성자를 사용하는 등 컬렉션 형식에 대한 추가 요구 사항은 다음 단원에서 자세히 설명합니다. 이렇게 하면 컬렉션 형식이 직렬화되고 역직렬화될 수 있습니다. 따라서 매개 변수가 없는 생성자가 없으므로 제네릭 ReadOnlyCollection<T>과 같은 일부 컬렉션은 직접 지원되지 않습니다. 이러한 제한을 해결하는 방법에 대한 자세한 내용은 이 항목의 뒷부분에 있는 "컬렉션 인터페이스 형식 및 읽기 전용 컬렉션 사용" 단원을 참조하십시오.

컬렉션에 포함된 형식은 데이터 계약 형식이거나 serialize할 수 있어야 합니다. 자세한 내용은 데이터 계약 직렬 변환기에서 지원하는 형식을 참조하세요.

유효한 것으로 간주되는 컬렉션과 그렇지 않은 컬렉션 그리고 컬렉션을 serialize하는 방법에 대한 자세한 내용은 이 항목에 있는 "고급 컬렉션 규칙" 섹션의 컬렉션 serialize에 대한 내용을 참조하세요.

교환 가능 컬렉션

동일한 형식의 모든 목록 컬렉션은 이 항목 뒷부분에서 설명하는 것처럼 CollectionDataContractAttribute 특성을 사용하여 사용자 지정되지 않는 한 동일한 데이터 계약을 가지는 것으로 간주됩니다. 예를 들어, 다음 데이터 계약은 동일합니다.

[DataContract(Name = "PurchaseOrder")]
public class PurchaseOrder1
{
    [DataMember]
    public string customerName;
    [DataMember]
    public Collection<Item> items;
    [DataMember]
    public string[] comments;
}

[DataContract(Name = "PurchaseOrder")]
public class PurchaseOrder2
{
    [DataMember]
    public string customerName;
    [DataMember]
    public List<Item> items;
    [DataMember]
    public BindingList<string> comments;
}
<DataContract(Name:="PurchaseOrder")>
Public Class PurchaseOrder1

    <DataMember()>
    Public customerName As String

    <DataMember()>
    Public items As Collection(Of Item)

    <DataMember()>
    Public comments() As String

End Class

<DataContract(Name:="PurchaseOrder")>
Public Class PurchaseOrder2

    <DataMember()>
    Public customerName As String

    <DataMember()>
    Public items As List(Of Item)

    <DataMember()>
    Public comments As BindingList(Of String)

End Class

두 데이터 계약 모두 다음 코드와 유사한 XML이 됩니다.

<PurchaseOrder>
    <customerName>...</customerName>
    <items>
        <Item>...</Item>
        <Item>...</Item>
        <Item>...</Item>
        ...
    </items>
    <comments>
        <string>...</string>
        <string>...</string>
        <string>...</string>
        ...
    </comments>
</PurchaseOrder>

예를 들어, 컬렉션 교환 가능성을 통해 서버의 성능에 맞게 최적화된 컬렉션 형식 및 클라이언트의 사용자 인터페이스 구성 요소에 바인딩되도록 디자인된 컬렉션 형식을 사용할 수 있습니다.

목록 컬렉션과 마찬가지로 동일한 키 및 값 형식이 있는 모든 사전 컬렉션은 CollectionDataContractAttribute 특성을 사용하여 사용자 지정되지 않는 한 동일한 데이터 계약을 가지는 것으로 간주됩니다.

컬렉션 일치에 있어서는 .NET 형식이 아닌 데이터 계약 형식만 중요합니다. 즉, Type1 및 Type2에 동일한 데이터 계약이 있는 경우 Type1의 컬렉션과 Type2의 컬렉션이 동일하다고 간주합니다.

제네릭이 아닌 컬렉션에는 Object형식의 제네릭 컬렉션과 동일한 데이터 계약이 있는 것으로 간주합니다. 예를 들어, ArrayList 의 데이터 계약 및 List<T> 의 제네릭 Object 은 동일합니다.

컬렉션 인터페이스 형식 및 읽기 전용 컬렉션 사용

또한 컬렉션 인터페이스 형식(IEnumerable, IDictionary, 제네릭 IDictionary<TKey,TValue>또는 이러한 인터페이스에서 파생된 인터페이스)에는 실제 컬렉션 형식의 컬렉션 데이터 계약과 동일한 컬렉션 데이터 계약이 있는 것으로 간주합니다. 따라서 serialize되는 형식을 컬렉션 인터페이스 형식으로 선언할 수 있으며, 결과는 실제 컬렉션 형식을 사용한 것과 동일합니다. 예를 들어, 다음 데이터 계약은 동일합니다.

[DataContract(Name="Customer")]
public class Customer1
{
    [DataMember]
    public string customerName;
    [DataMember]
    public Collection<Address> addresses;
}

[DataContract(Name="Customer")]
public class Customer2
{
    [DataMember]
    public string customerName;
    [DataMember]
    public ICollection<Address> addresses;
}
<DataContract(Name:="Customer")>
Public Class Customer1

    <DataMember()>
    Public customerName As String

    <DataMember()>
    Public addresses As Collection(Of Address)

End Class

<DataContract(Name:="Customer")>
Public Class Customer2

    <DataMember()>
    Public customerName As String

    <DataMember()>
    Public addresses As ICollection(Of Address)

End Class

serialization을 수행하는 동안 선언된 형식이 인터페이스인 경우 사용된 실제 인스턴스 형식은 해당 인터페이스를 구현하는 모든 형식이 될 수 있습니다. 앞에서 설명한 제한 사항(매개 변수가 없는 생성자 및 Add 메서드를 사용)은 적용되지 않습니다. 예를 들어, 제네릭 ReadOnlyCollection<T> 형식의 데이터 멤버를 직접 선언할 수 없는 경우에도 Customer2의 주소를 제네릭 주소 ReadOnlyCollection<T>의 인스턴스로 설정할 수 있습니다

deserialization을 수행하는 동안 선언된 형식이 인터페이스인 경우 serialization 엔진은 선언된 인터페이스를 구현하는 형식을 선택하고, 해당 형식은 인스턴스화됩니다. 데이터 계약 알려진 형식에서 설명한 알려진 형식 메커니즘은 여기에 영향을 주지 않으며, 선택한 형식은 WCF에 기본 제공됩니다.

컬렉션 형식 사용자 지정

여러 용도로 사용되는 CollectionDataContractAttribute 특성을 사용하여 컬렉션 형식을 사용자 지정할 수 있습니다.

컬렉션 형식을 사용자 지정하면 컬렉션 교환 가능성이 낮아지므로 가능하면 이 특성을 적용하지 않는 것이 좋습니다. 이 문제에 대한 자세한 내용은 이 항목의 뒷부분에 있는 "고급 컬렉션 규칙" 단원을 참조하세요.

컬렉션 데이터 계약 명명

컬렉션 형식의 명명 규칙은 Data Contract Names에서 설명한 대로 일반 데이터 계약 형식의 명명 규칙과 유사하지만, 다음과 같은 중요한 차이점이 몇 개 있습니다.

  • CollectionDataContractAttribute 특성은 DataContractAttribute 특성 대신 이름을 사용자 지정하는 데 사용됩니다. 또한 CollectionDataContractAttribute 특성에는 NameNamespace 속성이 있습니다.

  • CollectionDataContractAttribute 특성이 적용되지 않는 경우 컬렉션 형식의 기본 이름 및 네임스페이스는 컬렉션에 포함된 형식의 이름 및 네임스페이스에 따라 다릅니다. 컬렉션 형식의 이름 및 네임스페이스 자체는 컬렉션에 포함된 형식의 이름 및 네임스페이스에 영향을 주지 않습니다. 예를 보려면 다음 형식을 참조하세요.

    public CustomerList1 : Collection<string> {}
    public StringList1 : Collection<string> {}
    

두 형식의 데이터 계약 이름이 모두 "ArrayOfstring"이고 "CustomerList1" 또는 "StringList1"이 아닙니다. 즉, 루트 수준의 이러한 형식 중 하나를 serialize하면 다음 코드와 유사한 XML이 생성됩니다.

<ArrayOfstring>
    <string>...</string>
    <string>...</string>
    <string>...</string>
    ...
</ArrayOfstring>

문자열의 목록을 나타내는 사용자 지정되지 않은 형식에 동일한 데이터 계약 및 XML 표현이 있도록 이 명명 규칙을 선택했습니다. 이렇게 하면 컬렉션 교환이 가능하게 됩니다. 이 예제에서 CustomerList1과 StringList1은 완벽하게 교환 가능합니다.

그러나 CollectionDataContractAttribute 특성이 적용된 경우 속성을 특성에 설정하지 않아도 컬렉션은 사용자 지정된 컬렉션 데이터 계약이 됩니다. 따라서 컬렉션 데이터 계약의 이름 및 네임스페이스는 컬렉션 형식 자체에 따라 달라집니다. 예를 보려면 다음 형식을 참조하십시오.

[CollectionDataContract]
public class CustomerList2 : Collection<string> {}
<CollectionDataContract()>
Public Class CustomerList2
    Inherits Collection(Of String)
End Class

serialize된 결과 XML은 다음과 유사합니다.

<CustomerList2>
    <string>...</string>
    <string>...</string>
    <string>...</string>
    ...
</CustomerList2>

결과 XML은 사용자 지정되지 않은 형식의 XML 표현과 더 이상 동일하지 않습니다.

  • NameNamespace 속성을 사용하여 명명을 추가로 사용자 지정할 수 있습니다. 다음 클래스를 참조하십시오.

    [CollectionDataContract(Name="cust_list")]
    public class CustomerList3 : Collection<string> {}
    
    <CollectionDataContract(Name:="cust_list")>
    Public Class CustomerList3
        Inherits Collection(Of String)
    End Class
    

결과 XML은 다음과 유사합니다.

<cust_list>
    <string>...</string>
    <string>...</string>
    <string>...</string>
    ...
</cust_list>

자세한 내용은 이 항목의 뒷부분에 있는 "고급 컬렉션 규칙" 단원을 참조하세요.

목록 컬렉션의 반복되는 요소 이름 사용자 지정

목록 컬렉션에는 반복되는 항목이 있습니다. 일반적으로 반복되는 각 항목은 컬렉션에 포함된 형식의 데이터 계약 이름에 따라 명명된 요소로 표시됩니다.

CustomerList 예제에서 컬렉션에는 문자열이 있습니다. 문자열 기본 형식의 데이터 계약 이름은 "문자열"이므로 반복되는 요소는 "<string>"입니다.

그러나 ItemName 특성의 CollectionDataContractAttribute 속성을 사용하여 이 반복되는 요소 이름을 사용자 지정할 수 있습니다. 예를 보려면 다음 형식을 참조하십시오.

[CollectionDataContract(ItemName="customer")]
public class CustomerList4 : Collection<string>  {}
<CollectionDataContract(ItemName:="customer")>
Public Class CustomerList4
    Inherits Collection(Of String)
End Class

결과 XML은 다음과 유사합니다.

<CustomerList4>
    <customer>...</customer>
    <customer>...</customer>
    <customer>...</customer>
    ...
</CustomerList4>

반복되는 요소의 네임스페이스는 앞에서 설명한 대로 Namespace 속성을 사용하여 사용자 지정할 수 있는 컬렉션 데이터 계약의 네임스페이스와 항상 같습니다.

사전 컬렉션 사용자 지정

사전 컬렉션은 기본적으로 항목의 목록이며 각 항목에는 키 다음에 값이 있습니다. 일반 목록과 마찬가지로 ItemName 속성을 사용하여 반복되는 요소에 해당하는 요소 이름을 변경할 수 있습니다.

또한 KeyNameValueName 속성을 사용하여 키 및 값을 나타내는 요소 이름을 변경할 수 있습니다. 이러한 요소의 네임스페이스는 컬렉션 데이터 계약의 네임스페이스와 같습니다.

예를 보려면 다음 형식을 참조하십시오.

[CollectionDataContract
    (Name = "CountriesOrRegionsWithCapitals",
    ItemName = "entry",
    KeyName = "countryorregion",
    ValueName = "capital")]
public class CountriesOrRegionsWithCapitals2 : Dictionary<string, string> { }
<CollectionDataContract(Name:="CountriesOrRegionsWithCapitals",
                        ItemName:="entry", KeyName:="countryorregion",
                        ValueName:="capital")>
Public Class CountriesOrRegionsWithCapitals2
    Inherits Dictionary(Of String, String)
End Class

serialize된 결과 XML은 다음과 유사합니다.

<CountriesOrRegionsWithCapitals>
    <entry>
        <countryorregion>USA</countryorregion>
        <capital>Washington</capital>
    </entry>
    <entry>
        <countryorregion>France</countryorregion>
        <capital>Paris</capital>
    </entry>
    ...
</CountriesOrRegionsWithCapitals>

사전 컬렉션에 대한 자세한 내용은 이 항목의 뒷부분에 있는 "고급 컬렉션 규칙" 단원을 참조하세요.

컬렉션 및 알려진 형식

컬렉션 형식을 다른 컬렉션이나 컬렉션 인터페이스 대신 다형적으로 사용하는 경우 알려진 형식에 추가할 필요는 없습니다. 예를 들어, IEnumerable 형식의 데이터 멤버를 선언하고 이를 사용하여 ArrayList의 인스턴스를 보내는 경우 ArrayList 를 알려진 형식에 추가할 필요가 없습니다.

비컬렉션 형식 대신 다형적으로 컬렉션을 사용하는 경우에는 알려진 형식에 추가해야 합니다. 예를 들어, Object 형식의 데이터 멤버를 선언하고 이를 사용하여 ArrayList의 인스턴스를 보내는 경우 알려진 형식에 ArrayList 를 추가합니다.

그러나 동일한 컬렉션을 다형적으로 serialize할 수는 없습니다. 예를 들어, ArrayList 를 위 예제의 알려진 형식의 목록에 추가하는 경우 해당 목록에 동일한 데이터 계약이 있더라도 Array of Object 클래스를 할당할 수 없습니다. 따라서 비컬렉션 형식에 대한 serialization에서 알려진 형식의 일반 동작과 차이는 없지만, 컬렉션이 동일한 경우가 매우 일반적이기 때문에 컬렉션의 경우 이 동작을 이해하는 것이 특히 중요합니다.

serialization을 수행하는 동안 지정된 데이터 계약의 지정된 범위에서 하나의 형식만을 알 수 있으며 모든 동일한 컬렉션에는 같은 데이터 계약이 있습니다. 따라서 위 예제에서 ArrayListArray of Object 모두를 같은 범위의 알려진 형식에 추가할 수 없습니다. 이 동작은 비컬렉션 형식에 대한 알려진 형식 동작과 동일하지만, 컬렉션의 경우 이를 이해하는 것이 특히 중요합니다.

알려진 형식은 또한 컬렉션의 내용에 필요합니다. 예를 들어, ArrayListType1Type2의 인스턴스가 실제로 있는 경우 이 두 가지 형식 모두 알려진 형식에 추가해야 합니다.

다음 예제에서는 컬렉션 및 알려진 형식을 사용하여 올바르게 생성된 개체 그래프를 보여 줍니다. 일반적으로 실제 애플리케이션에서는 다음 데이터 멤버를 Object로 정의하지 않고 알려진 형식/다형성 문제가 없기 때문에 이 예제는 실제와 다소 거리가 있습니다.

[DataContract]
public class Employee
{
    [DataMember]
    public string name = "John Doe";
    [DataMember]
    public Payroll payrollRecord;
    [DataMember]
    public Training trainingRecord;
}

[DataContract]
[KnownType(typeof(int[]))] //required because int[] is used polymorphically
[KnownType(typeof(ArrayList))] //required because ArrayList is used polymorphically
public class Payroll
{
    [DataMember]
    public object salaryPayments = new int[12];
    //float[] not needed in known types because polymorphic assignment is to another collection type
    [DataMember]
    public IEnumerable<float> stockAwards = new float[12];
    [DataMember]
    public object otherPayments = new ArrayList();
}

[DataContract]
[KnownType(typeof(List<object>))]
//required because List<object> is used polymorphically
//does not conflict with ArrayList above because it's a different scope,
//even though it's the same data contract
[KnownType(typeof(InHouseTraining))] //Required if InHouseTraining can be used in the collection
[KnownType(typeof(OutsideTraining))] //Required if OutsideTraining can be used in the collection
public class Training
{
    [DataMember]
    public object training = new List<object>();
}

[DataContract]
public class InHouseTraining
{
    //code omitted
}

[DataContract]
public class OutsideTraining
{
    //code omitted
}
<DataContract()>
Public Class Employee

    <DataMember()>
    Public name As String = "John Doe"

    <DataMember()>
    Public payrollRecord As Payroll

    <DataMember()>
    Public trainingRecord As Training

End Class

<DataContract(), KnownType(GetType(Integer())), KnownType(GetType(ArrayList))>
Public Class Payroll

    <DataMember()>
    Public salaryPayments As Object = New Integer(11) {}

    'float[] not needed in known types because polymorphic assignment is to another collection type
    <DataMember()>
    Public stockAwards As IEnumerable(Of Single) = New Single(11) {}

    <DataMember()>
    Public otherPayments As Object = New ArrayList()

End Class

'required because List<object> is used polymorphically
'does not conflict with ArrayList above because it's a different scope, 
'even though it's the same data contract
<DataContract(), KnownType(GetType(List(Of Object))),
                 KnownType(GetType(InHouseTraining)),
                 KnownType(GetType(OutsideTraining))>
Public Class Training
    <DataMember()>
    Public training As Object = New List(Of Object)()
End Class

<DataContract()>
Public Class InHouseTraining
    'code omitted…
End Class

<DataContract()>
Public Class OutsideTraining
    'code omitted…
End Class

deserialization에서 선언된 형식이 컬렉션 형식이면 실제로 보낸 형식과 관계없이 선언된 형식이 인스턴스화됩니다. 선언된 형식이 컬렉션 인터페이스이면 역직렬 변환기에서는 알려진 형식과 관계없이 인스턴스화할 형식을 선택합니다.

또한 deserialization에서 선언된 형식이 컬렉션 형식은 아니지만 컬렉션 형식을 보내는 경우 일치하는 컬렉션 형식이 알려진 형식 목록에서 선택됩니다. deserialization에서 컬렉션 인터페이스 형식을 알려진 형식 목록에 추가할 수 있습니다. 이 경우 deserialization 엔진은 인스턴스화할 형식을 다시 선택합니다.

컬렉션 및 NetDataContractSerializer 클래스

NetDataContractSerializer 클래스가 사용 중인 경우 배열이 아닌 사용자 지정되지 않은 컬렉션 형식( CollectionDataContractAttribute 특성이 없는 컬렉션)은 원래의 특수한 의미를 잃게 됩니다.

SerializableAttribute 특성으로 표시된 사용자 지정되지 않은 컬렉션 형식은 NetDataContractSerializer 특성이나 SerializableAttribute 인터페이스 규칙에 따라 ISerializable 클래스로 여전히 serialize할 수 있습니다.

사용자 지정된 컬렉션 형식, 컬렉션 인터페이스 및 배열은 NetDataContractSerializer 클래스가 사용 중인 경우에도 컬렉션으로서 계속 처리됩니다.

컬렉션 및 스키마

모든 동일한 컬렉션에는 동일한 표현의 XSD(XML 스키마 정의 언어) 스키마가 있습니다. 이 때문에 일반적으로 서버의 컬렉션 형식과 동일한 컬렉션 형식을 생성된 클라이언트 코드에서 얻을 수 없습니다. 예를 들어, 서버에서 정수 데이터 멤버의 제네릭 List<T> 와 함께 데이터 계약을 사용할 수 있지만, 생성된 클라이언트 코드에서 동일한 데이터 멤버가 정수 배열이 될 수 있습니다.

사전 컬렉션은 사전임을 나타내는 WCF 관련 스키마 주석으로 표시됩니다. 그렇지 않으면 키 및 값을 가진 항목이 포함된 단순 목록과 사전 컬렉션이 구분될 수 없습니다. 데이터 계약 스키마에서 컬렉션이 표시되는 방법에 대한 정확한 설명은 Data Contract Schema Reference를 참조하십시오.

기본적으로 가져온 코드의 사용자 지정되지 않은 컬렉션에 대해서는 형식이 생성되지 않습니다. 목록 컬렉션 형식의 데이터 멤버는 배열로 가져오며, 사전 컬렉션 형식의 데이터 멤버는 제네릭 사전으로 가져옵니다.

그러나 사용자 지정된 컬렉션의 경우 CollectionDataContractAttribute 특성으로 표시되는 별도의 형식이 생성됩니다. (스키마에서 사용자 지정된 컬렉션 형식은 기본 네임스페이스, 이름, 반복 요소 이름 또는 키/값 요소 이름을 사용하지 않는 컬렉션 형식입니다.) 이러한 형식은 목록 형식의 경우 제네릭 List<T>에서 파생되고 사전 형식의 경우 제네릭 사전에서 파생되는 빈 형식입니다.

예를 들어, 서버에 다음 형식이 있을 수 있습니다.

[DataContract]
public class CountryOrRegion
{
    [DataMember]
    public Collection<string> officialLanguages;
    [DataMember]
    public List<DateTime> holidays;
    [DataMember]
    public CityList cities;
    [DataMember]
    public ArrayList otherInfo;
}

public class Person
{
    public Person(string fName, string lName)
    {
        this.firstName = fName;
        this.lastName = lName;
    }

    public string firstName;
    public string lastName;
}

public class PeopleEnum : IEnumerator
{
    public Person[] _people;

    // Enumerators are positioned before the first element
    // until the first MoveNext() call.
    int position = -1;

    public PeopleEnum(Person[] list)
    {
        _people = list;
    }

    public bool MoveNext()
    {
        position++;
        return (position < _people.Length);
    }

    public void Reset()
    {
        position = -1;
    }

    public object Current
    {
        get
        {
            try
            {
                return _people[position];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}

[CollectionDataContract(Name = "Cities", ItemName = "city", KeyName = "cityName", ValueName = "population")]
public class CityList : IDictionary<string, int>, IEnumerable<System.Collections.Generic.KeyValuePair<string, int>>
{
    private Person[] _people = null;

    public bool ContainsKey(string s) { return true; }
    public bool Contains(string s) { return true; }
    public bool Contains(KeyValuePair<string, int> item) { return (true); }
    public void Add(string key, int value) { }
    public void Add(KeyValuePair<string, int> keykValue) { }
    public bool Remove(string s) { return true; }
    public bool TryGetValue(string d, out int i)
    {
        i = 0; return (true);
    }

    /*
    [TypeConverterAttribute(typeof(SynchronizationHandlesTypeConverter))]
    public ICollection<string> SynchronizationHandles {
        get { return (System.Collections.Generic.ICollection<string>) new Stack<string> (); }
        set { }
    }*/

    public ICollection<string> Keys
    {
        get
        {
            return (System.Collections.Generic.ICollection<string>)new Stack<string>();
        }
    }

    public int this[string s]
    {
        get
        {
            return 0;
        }
        set
        {
        }
    }

    public ICollection<int> Values
    {
        get
        {
            return (System.Collections.Generic.ICollection<int>)new Stack<string>();
        }
    }

    public void Clear() { }
    public void CopyTo(KeyValuePair<string, int>[] array, int index) { }
    public bool Remove(KeyValuePair<string, int> item) { return true; }
    public int Count { get { return 0; } }
    public bool IsReadOnly { get { return true; } }

    IEnumerator<KeyValuePair<string, int>>
        System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, int>>.GetEnumerator()
    {
        return (IEnumerator<KeyValuePair<string, int>>)new PeopleEnum(_people); ;
    }

    public IEnumerator GetEnumerator()
    {
        return new PeopleEnum(_people);
    }
}

<DataContract()>
Public Class CountryOrRegion

    <DataMember()>
    Public officialLanguages As Collection(Of String)

    <DataMember()>
    Public holidays As List(Of DateTime)

    <DataMember()>
    Public cities As CityList

    <DataMember()>
    Public otherInfo As ArrayList

End Class

Public Class Person
    Public Sub New(ByVal fName As String, ByVal lName As String)
        Me.firstName = fName
        Me.lastName = lName
    End Sub

    Public firstName As String
    Public lastName As String
End Class

Public Class PeopleEnum
    Implements IEnumerator

    Public _people() As Person
    ' Enumerators are positioned before the first element
    ' until the first MoveNext() call.
    Private position As Integer = -1

    Public Sub New(ByVal list() As Person)
        _people = list
    End Sub

    Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
        position += 1
        Return position < _people.Length
    End Function

    Public Sub Reset() Implements IEnumerator.Reset
        position = -1
    End Sub

    Public ReadOnly Property Current() As Object Implements IEnumerator.Current
        Get
            Try
                Return _people(position)
            Catch e1 As IndexOutOfRangeException
                Throw New InvalidOperationException()
            End Try
        End Get
    End Property
End Class

<CollectionDataContract(Name:="Cities",
                        ItemName:="city",
                        KeyName:="cityName",
                        ValueName:="population")>
Public Class CityList
    Implements IDictionary(Of String, Integer), IEnumerable(Of System.Collections.Generic.KeyValuePair(Of String, Integer))

    Private _people() As Person = Nothing

    Public Function ContainsKey(ByVal s As String) As Boolean Implements IDictionary(Of String, Integer).ContainsKey
        Return True
    End Function

    Public Function Contains(ByVal s As String) As Boolean
        Return True
    End Function

    Public Function Contains(ByVal item As KeyValuePair(Of String, Integer)) As Boolean Implements IDictionary(Of String, Integer).Contains
        Return (True)
    End Function

    Public Sub Add(ByVal key As String,
                   ByVal value As Integer) Implements IDictionary(Of String, Integer).Add
    End Sub

    Public Sub Add(ByVal keykValue As KeyValuePair(Of String, Integer)) Implements IDictionary(Of String, Integer).Add
    End Sub

    Public Function Remove(ByVal s As String) As Boolean Implements IDictionary(Of String, Integer).Remove
        Return True
    End Function

    Public Function TryGetValue(ByVal d As String,
                                <System.Runtime.InteropServices.Out()> ByRef i As Integer) _
                                As Boolean Implements IDictionary(Of String, Integer).TryGetValue
        i = 0
        Return (True)
    End Function

    Public ReadOnly Property Keys() As ICollection(Of String) Implements IDictionary(Of String, Integer).Keys
        Get
            Return CType(New Stack(Of String)(), System.Collections.Generic.ICollection(Of String))
        End Get
    End Property

    Default Public Property Item(ByVal s As String) As Integer Implements IDictionary(Of String, Integer).Item
        Get
            Return 0
        End Get
        Set(ByVal value As Integer)
        End Set
    End Property

    Public ReadOnly Property Values() As ICollection(Of Integer) Implements IDictionary(Of String, Integer).Values
        Get
            Return CType(New Stack(Of String)(), System.Collections.Generic.ICollection(Of Integer))
        End Get
    End Property

    Public Sub Clear() Implements IDictionary(Of String, Integer).Clear
    End Sub

    Public Sub CopyTo(ByVal array() As KeyValuePair(Of String, Integer),
                      ByVal index As Integer) Implements IDictionary(Of String, Integer).CopyTo
    End Sub

    Public Function Remove(ByVal item As KeyValuePair(Of String, Integer)) As Boolean Implements IDictionary(Of String, Integer).Remove
        Return True
    End Function

    Public ReadOnly Property Count() As Integer Implements IDictionary(Of String, Integer).Count
        Get
            Return 0
        End Get
    End Property

    Public ReadOnly Property IsReadOnly() As Boolean Implements IDictionary(Of String, Integer).IsReadOnly
        Get
            Return True
        End Get
    End Property

    Private Function IEnumerable_GetEnumerator() As IEnumerator(Of KeyValuePair(Of String, Integer)) _
        Implements System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of String, Integer)).GetEnumerator

        Return CType(New PeopleEnum(_people), IEnumerator(Of KeyValuePair(Of String, Integer)))
    End Function

    Public Function GetEnumerator() As IEnumerator Implements System.Collections.IEnumerable.GetEnumerator

        Return New PeopleEnum(_people)

    End Function

End Class

스키마를 내보내고 다시 가져온 경우 생성되는 클라이언트 코드는 다음과 유사합니다. 읽기 용이하도록 속성 대신 필드가 표시되어 있습니다.

[DataContract]
public class CountryOrRegion2
{
    [DataMember]
    public string[] officialLanguages;
    [DataMember]
    public DateTime[] holidays;
    [DataMember]
    public Cities cities;
    [DataMember]
    public object[] otherInfo;
}

[CollectionDataContract(ItemName = "city", KeyName = "cityName", ValueName = "population")]
public class Cities : Dictionary<string, int> { }
<DataContract()>
Public Class CountryOrRegion2
    <DataMember()>
    Public officialLanguages() As String
    <DataMember()>
    Public holidays() As DateTime
    <DataMember()>
    Public cities As Cities
    <DataMember()>
    Public otherInfo() As Object
End Class

<CollectionDataContract(ItemName:="city", KeyName:="cityName", ValueName:="population")>
Public Class Cities
    Inherits Dictionary(Of String, Integer)
End Class

생성된 코드에서 기본 형식 대신 다른 형식을 사용해야 하는 경우가 있습니다. 예를 들어, 사용자 인터페이스 구성 요소에 쉽게 바인딩할 수 있도록 데이터 멤버의 일반 배열 대신 제네릭 BindingList<T> 를 사용해야 하는 경우입니다.

생성할 컬렉션 형식을 선택하려면 스키마를 가져올 때 사용할 컬렉션 형식의 목록을 ReferencedCollectionTypes 개체의 ImportOptions 속성에 전달합니다. 이러한 형식을 참조된 컬렉션 형식이라고 합니다.

제네릭 형식을 참조할 때 해당 제네릭 형식은 완전 개방형 제네릭 형식 또는 완전 폐쇄형 제네릭 형식이어야 합니다.

참고 항목

Svcutil.exe 도구를 사용하는 경우 /collectionType 명령줄 스위치(약식: /ct)를 사용하여 이 참조를 수행할 수 있습니다. 또한 /reference 스위치(약식: /r)를 사용하여 참조된 컬렉션 형식에 대한 어셈블리를 지정해야 합니다. 형식이 제네릭이면 뒤에는 역따옴표 및 제네릭 매개 변수의 수가 와야 합니다. 역따옴표(`)를 작은따옴표(‘) 문자와 혼동해서는 안 됩니다. /collectionType 스위치를 두 번 이상 사용하여 여러 개의 참조된 컬렉션 형식을 지정할 수 있습니다.

예를 들어, 모든 목록을 제네릭 List<T>로 가져오려면 다음을 사용합니다.

svcutil.exe MyService.wsdl MyServiceSchema.xsd /r:C:\full_path_to_system_dll\System.dll /ct:System.Collections.Generic.List`1

컬렉션을 가져올 때 이 참조된 컬렉션 형식 목록을 검색한 다음 사용자 지정되지 않은 컬렉션의 경우 데이터 멤버 형식으로 컬렉션을 찾거나, 사용자 지정된 컬렉션의 경우 파생될 기본 형식으로 컬렉션을 찾아 가장 일치하는 컬렉션을 사용합니다. 사전은 사전에 대해서만 일치하며 목록은 목록에 대해서만 일치합니다.

예를 들어, 제네릭 BindingList<T>Hashtable 을 참조된 형식 목록에 추가하면 앞의 예제에서 생성된 클라이언트 코드는 다음과 유사합니다.

[DataContract]
public class CountryOrRegion3
{
    [DataMember]
    public BindingList<string> officialLanguages;
    [DataMember]
    public BindingList<DateTime> holidays;
    [DataMember]
    public Cities cities;
    [DataMember]
    public BindingList<object> otherInfo;
}

[CollectionDataContract(ItemName = "city", KeyName = "cityName", ValueName = "population")]
public class Cities3 : Hashtable { }
<DataContract()>
Public Class CountryOrRegion3

    <DataMember()>
    Public officialLanguages As BindingList(Of String)

    <DataMember()>
    Public holidays As BindingList(Of DateTime)

    <DataMember()>
    Public cities As Cities

    <DataMember()>
    Public otherInfo As BindingList(Of Object)

End Class

<CollectionDataContract(ItemName:="city",
                        KeyName:="cityName",
                        ValueName:="population")>
Public Class Cities3
    Inherits Hashtable
End Class

컬렉션 인터페이스 형식을 참조된 컬렉션 형식의 일부로 지정할 수 있지만 Add 메서드 또는 public 생성자가 없는 컬렉션 형식과 같은 잘못된 컬렉션 형식을 지정할 수는 없습니다.

폐쇄형 제네릭이 가장 일치하는 항목으로 간주됩니다. 제네릭이 아닌 형식은 Object의 폐쇄형 제네릭과 동일한 것으로 간주됩니다. 예를 들어, List<T> 의 제네릭 DateTime, 제네릭 BindingList<T> (개방형 제네릭) 및 ArrayList 형식이 참조된 컬렉션 형식이면 다음이 생성됩니다.

[DataContract]
public class CountryOrRegion4
{
    [DataMember]
    public string[] officialLanguages;
    [DataMember]
    public DateTime[] holidays;
    [DataMember]
    public Cities cities;
    [DataMember]
    public object[] otherInfo;
}

[CollectionDataContract(ItemName = "city", KeyName = "cityName", ValueName = "population")]
public class Cities4 : Dictionary<string, int> { }
<DataContract()>
Public Class CountryOrRegion4

    <DataMember()>
    Public officialLanguages() As String

    <DataMember()>
    Public holidays() As DateTime

    <DataMember()>
    Public cities As Cities

    <DataMember()>
    Public otherInfo() As Object

End Class

<CollectionDataContract(ItemName:="city",
                        KeyName:="cityName",
                        ValueName:="population")>
Public Class Cities4
    Inherits Dictionary(Of String, Integer)
End Class

목록 컬렉션에서는 다음 표에 있는 것과 같은 경우만 지원됩니다.

참조된 형식 참조된 형식으로 구현된 인터페이스 예시 처리되는 형식
제네릭이 아닌 형식 또는 폐쇄형 제네릭 형식(매개 변수 수에는 제한 없음) 제네릭이 아닌 형식 MyType : IList

또는

MyType<T> : IList

여기서 T= int
Object 의 폐쇄형 제네릭 형식(예: IList<object>)
제네릭이 아닌 형식 또는 폐쇄형 제네릭 형식(컬렉션 형식과 일치하지 않아도 되는 임의의 수의 매개 변수) 폐쇄형 제네릭 형식 MyType : IList<string>

또는

MyType<T> : IList<string> 여기서 T=int
폐쇄형 제네릭 형식(예: IList<string>)
여러 개의 매개 변수가 있는 폐쇄형 제네릭 형식 형식의 매개 변수 중 하나를 사용하는 개방형 제네릭 형식 MyType<T,U,V> : IList<U>

여기서 T=int, U=string, V=bool
폐쇄형 제네릭 형식(예: IList<string>)
하나의 매개 변수가 있는 개방형 제네릭 형식 형식의 매개 변수를 사용하는 개방형 제네릭 형식 MyType<T> : IList<T>, T는 개방형 개방형 제네릭 형식(예: IList<T>)

형식에서 두 개 이상의 목록 컬렉션 인터페이스를 구현하는 경우 다음 제한 사항이 적용됩니다.

  • 형식에서 제네릭 IEnumerable<T> 또는 파생된 인터페이스를 다른 형식으로 여러 번 구현하는 경우 해당 형식은 유효한 참조된 컬렉션 형식으로 간주되지 않고 무시됩니다. 일부 구현이 잘못된 경우 또는 개방형 제네릭을 사용하는 경우에도 마찬가지입니다. 예를 들어, IEnumerable<T> 의 제네릭 int 및 T의 제네릭 IEnumerable<T> 을 구현하는 형식은 int 를 허용하는 Add 메서드, T 형식의 매개 변수를 허용하는 int 메서드 또는 두 메서드 모두가 해당 형식에 있는지 여부와 관계없이 Add 또는 다른 형식의 참조된 컬렉션으로 사용되지 않습니다.

  • 형식에서 IList및 제네릭 컬렉션 인터페이스를 구현하는 경우 제네릭 컬렉션 인터페이스가 Object형식의 폐쇄형 제네릭이 아니면 해당 형식은 참조된 컬렉션 형식으로 사용되지 않습니다.

사전 컬렉션에서는 다음 표에 있는 것과 같은 경우만 지원됩니다.

참조된 형식 참조된 형식으로 구현된 인터페이스 예시 처리되는 형식
제네릭이 아닌 형식 또는 폐쇄형 제네릭 형식(매개 변수 수에는 제한 없음) IDictionary MyType : IDictionary

또는

MyType<T> : IDictionary 여기서 T=int
폐쇄형 제네릭 형식(예: IDictionary<object,object>)
폐쇄형 제네릭 형식(여러 개의 매개 변수) IDictionary<TKey,TValue>, 폐쇄형 MyType<T> : IDictionary<string, bool> 여기서 T=int 폐쇄형 제네릭 형식(예: IDictionary<string,bool>)
폐쇄형 제네릭 형식(여러 개의 매개 변수) 제네릭 IDictionary<TKey,TValue>, 값 또는 키 중 하나가 폐쇄형이며, 나머지 하나는 개방형이고 형식의 매개 변수 중 하나를 사용 MyType<T,U,V> : IDictionary<string,V> 여기서 T=int, U=float, V=bool

또는

MyType<Z> : IDictionary<Z,bool> 여기서 Z=string
폐쇄형 제네릭 형식(예: IDictionary<string,bool>)
폐쇄형 제네릭 형식(여러 개의 매개 변수) 제네릭 IDictionary<TKey,TValue>, 키와 값 모두 개방형이고 각각은 형식의 매개 변수 중 하나를 사용 MyType<T,U,V> : IDictionary<V,U> 여기서 T=int, U=bool, V=string 폐쇄형 제네릭 형식(예: IDictionary<string,bool>)
개방형 제네릭 형식(두 개의 매개 변수) 제네릭 IDictionary<TKey,TValue>, 개방형, 형식의 제네릭 매개 변수가 나타나는 순서대로 두 개의 매개 변수 모두 사용 MyType<K,V> : IDictionary<K,V>, K와 V 모두 개방형 개방형 제네릭 형식(예: IDictionary<K,V>)

형식에서 IDictionary 및 제네릭 IDictionary<TKey,TValue>를 모두 구현하는 경우 제네릭 IDictionary<TKey,TValue> 만 고려됩니다.

부분 제네릭 형식의 참조는 지원되지 않습니다.

예를 들어, 중복은 허용되지 않으므로 List<T> 의 제네릭 IntegerInteger 의 제네릭 컬렉션을 ReferencedCollectionTypes에 모두 추가할 수는 없습니다. 이는 정수 목록이 스키마에 있는 경우 사용할 대상을 결정할 수 없기 때문입니다. 중복 문제를 노출하는 형식이 스키마에 있는 경우에만 중복이 감지됩니다. 예를 들어, 가져오는 스키마에 정수 목록이 없는 경우 List<T> 의 제네릭 IntegerInteger 에 있는 ReferencedCollectionTypes의 제네릭 컬렉션을 모두 포함할 수 있지만 둘 다 영향을 주지 않습니다.

고급 컬렉션 규칙

컬렉션 serialize

컬렉션 serialization 규칙 목록은 다음과 같습니다.

  • 컬렉션의 컬렉션이 있는 컬렉션 형식의 결합이 허용됩니다. 가변 배열은 컬렉션의 컬렉션으로 처리됩니다. 다차원 배열은 지원되지 않습니다.

  • 바이트의 배열 및 XmlNode 의 배열은 컬렉션이 아닌 기본 형식으로 처리되는 특수 배열 형식입니다. 바이트의 배열을 serialize하면 각 바이트에 대한 별도의 요소 대신 Base64 인코딩된 데이터의 청크가 포함된 하나의 XML 요소가 됩니다. XmlNode 배열을 처리하는 방법에 대한 자세한 내용은 데이터 계약의 XML 및 ADO.NET 형식을 참조하세요. 물론 이러한 특수 형식은 컬렉션에 참여할 수 있습니다. 바이트 배열의 배열은 여러 XML 요소가 되며 각 요소는 Base64 인코딩된 데이터의 청크를 포함합니다.

  • DataContractAttribute 특성이 컬렉션 형식에 적용되는 경우 해당 형식은 컬렉션이 아닌 일반 데이터 계약 형식으로 처리됩니다.

  • 컬렉션 형식이 IXmlSerializable 인터페이스를 구현하는 경우 myType:IList<string>, IXmlSerializable형식이 지정된 다음 규칙이 적용됩니다.

    • 선언된 형식이 IList<string>인 경우 형식이 목록으로 serialize됩니다.

    • 선언된 형식이 myType인 경우 형식이 IXmlSerializable로 serialize됩니다.

    • 선언된 형식이 IXmlSerializable인 경우 IXmlSerializable로 serialize되지만 myType 을 알려진 형식 목록에 추가하는 경우에만 적용됩니다.

  • 컬렉션은 다음 표에 나와 있는 메서드를 사용하여 직렬화되고 역직렬화됩니다.

컬렉션 형식에서 구현하는 인터페이스 serialization에서 호출된 메서드 deserialization에서 호출된 메서드
제네릭 IDictionary<TKey,TValue> get_Keys, get_Values 제네릭 Add
IDictionary get_Keys, get_Values Add
제네릭 IList<T> 제네릭 IList<T> 인덱서 제네릭 Add
제네릭 ICollection<T> 열거자 제네릭 Add
IList IList 인덱서 Add
제네릭 IEnumerable<T> GetEnumerator 적절한 형식(제네릭 매개 변수의 형식 또는 기본 형식 중 하나)의 매개 변수 하나를 사용하는 Add 라는 비정적 메서드가 호출됩니다. 해당 메서드는 serialization 및 deserialization을 수행하는 동안 serializer에서 컬렉션 형식을 컬렉션으로 처리하도록 존재해야 합니다.
IEnumerable 및 여기서 파생된 ICollection GetEnumerator Add 형식의 매개 변수 하나를 사용하는 Object라는 비정적 메서드가 호출됩니다. 해당 메서드는 serialization 및 deserialization을 수행하는 동안 serializer에서 컬렉션 형식을 컬렉션으로 처리하도록 존재해야 합니다.

위 표에는 컬렉션 인터페이스의 우선 순위가 내림차순으로 나열되어 있습니다. 예를 들어, 형식에서 IList 및 제네릭 IEnumerable<T>을 모두 구현하는 경우 컬렉션은 다음과 같은 IList 규칙에 따라 직렬화되고 역직렬화됩니다.

  • deserialization에서 모든 컬렉션은 매개 변수가 없는 생성자를 호출하여 먼저 형식의 인스턴스를 만들어 역직렬화됩니다. 여기서 기본 생성자는 serialization 및 deserialization을 수행하는 동안 직렬 변환기에서 컬렉션 형식을 컬렉션으로 처리하도록 존재해야 합니다.

  • 동일한 제네릭 컬렉션 인터페이스가 두 번 이상 구현되고(예를 들어, 형식이 ICollection<T> 의 제네릭 IntegerICollection<T> 의 제네릭 String을 모두 구현하는 경우), 우선 순위가 더 높은 인터페이스가 없는 경우 컬렉션은 유효한 컬렉션으로 처리되지 않습니다.

  • 컬렉션 형식은 이 컬렉션 형식에 적용된 SerializableAttribute 특성을 가질 수 있으며, ISerializable 인터페이스를 구현할 수 있습니다. 이 특성 및 인터페이스가 모두 무시됩니다. 그러나 Add 메서드가 없는 경우와 같이 형식에서 컬렉션 형식 요구 사항을 충분히 충족하지 않는 경우 형식은 컬렉션 형식으로 간주되지 않으므로 SerializableAttribute 특성 및 ISerializable 인터페이스에 의해 형식이 serialize될 수 있는지 여부가 결정됩니다.

  • 컬렉션을 사용자 지정하기 위해 CollectionDataContractAttribute 특성을 컬렉션에 적용하면 위의 SerializableAttribute 대체 메커니즘이 제거됩니다. 대신 사용자 지정된 컬렉션에서 컬렉션 형식 요구 사항을 충족하지 않는 경우 InvalidDataContractException 예외가 throw됩니다. 예외 문자열에는 Add 메서드 없음, 매개 변수가 없는 생성자 없음과 같은 형식이 유효한 컬렉션으로 간주되지 않는 이유를 설명하는 정보가 종종 포함됩니다. 따라서 디버깅 목적으로 CollectionDataContractAttribute 특성을 적용하는 것이 유용합니다.

컬렉션 명명

컬렉션 명명 규칙 목록은 다음과 같습니다.

  • 기본 형식이 포함된 목록 컬렉션 데이터 계약 및 모든 사전 컬렉션 데이터 계약의 기본 네임스페이스는 Namespace를 사용하여 재정의되지 않는 한, http://schemas.microsoft.com/2003/10/Serialization/Arrays입니다. char, TimespanGuid 형식과 함께 기본 제공 XSD 형식에 매핑되는 형식은 이러한 목적으로 기본 형식으로 간주됩니다.

  • 기본 형식이 아닌 형식이 포함된 컬렉션 형식의 기본 네임스페이스는 Namespace를 사용하여 재정의되지 않는 한 컬렉션에 포함된 형식의 데이터 계약 네임스페이스와 동일합니다.

  • 목록 컬렉션 데이터 계약의 기본 이름은 Name을 사용하여 재정의되지 않는 한 컬렉션에 포함된 형식의 데이터 계약 이름과 결합된 문자열인 "ArrayOf"입니다. 예를 들어, 정수의 제네릭 목록에 대한 데이터 계약 이름은 "ArrayOfint"입니다. Object 의 데이터 계약 이름은 "anyType"이므로 ArrayList 와 같은 제네릭이 아닌 목록의 데이터 계약 이름은 "ArrayOfanyType"입니다.

사전 컬렉션 데이터 계약의 기본 이름은 Name을 사용하여 재정의되지 않는 한 값 형식의 데이터 계약 이름 앞에 나오는 키 형식의 데이터 계약 이름과 결합된 문자열 "ArrayOfKeyValueOf"입니다. 예를 들어, 문자열 및 정수의 제네릭 사전에 대한 데이터 계약 이름은 "ArrayOfKeyValueOfstringint"입니다. 또한 키 또는 값 형식 중 하나가 기본 형식이 아닌 경우 키 및 값 형식의 데이터 계약 네임스페이스의 네임스페이스 해시가 이름에 추가됩니다. 네임스페이스 해시에 대한 자세한 내용은 데이터 계약 이름을 참조하세요.

각 사전 컬렉션 데이터 계약에는 사전에 있는 하나의 항목을 나타내는 도우미 데이터 계약이 있습니다. 이 계약의 이름은 "ArrayOf" 접두사를 제외하고 사전 데이터 계약과 동일하며 네임스페이스는 사전 데이터 계약과 동일합니다. 예를 들어, "ArrayOfKeyValueOfstringint" 사전 데이터 계약의 경우 "KeyValueofstringint" 데이터 계약은 사전에 있는 하나의 항목을 나타냅니다. 다음 단원에서 설명한 대로 ItemName 속성을 사용하여 이 데이터 계약의 이름을 사용자 지정할 수 있습니다.

제네릭 형식 명명 규칙은 Data Contract Names에서 설명한 대로 컬렉션 형식에 완전히 적용됩니다. 즉, 이름 내에 중괄호를 사용하여 제네릭 형식 매개 변수를 나타낼 수 있습니다. 그러나 괄호 내의 수는 컬렉션 내에 포함된 형식이 아닌 제네릭 매개 변수를 가리킵니다.

컬렉션 사용자 지정

CollectionDataContractAttribute 특성은 다음과 같이 사용할 수 없으며, 다음과 같이 사용된 경우 InvalidDataContractException 예외가 발생합니다.

다형성 규칙

이미 설명한 바와 같이 CollectionDataContractAttribute 특성을 사용하여 컬렉션을 사용자 지정하면 컬렉션 교환 가능성에 방해가 될 수 있습니다. 사전 컬렉션에서 키 및 값 이름뿐만 아니라 사전 컬렉션의 이름, 네임스페이스, 항목 이름이 일치하는 경우에만 사용자 지정된 두 개의 컬렉션 형식을 동일한 것으로 간주할 수 있습니다.

사용자 지정으로 인해 두 개 중 한 컬렉션 데이터 계약이 필요한 곳에 다른 나머지 컬렉션 데이터 계약을 잘못 사용할 수 있습니다. 이러한 경우가 발생해서는 안 됩니다. 다음 형식을 참조하십시오.

[DataContract]
public class Student
{
    [DataMember]
    public string name;
    [DataMember]
    public IList<int> testMarks;
}
public class Marks1 : List<int> {}
[CollectionDataContract(ItemName="mark")]
public class Marks2 : List<int> {}
<DataContract()>
Public Class Student

    <DataMember()>
    Public name As String

    <DataMember()>
    Public testMarks As IList(Of Integer)

End Class

Public Class Marks1
    Inherits List(Of Integer)
End Class

<CollectionDataContract(ItemName:="mark")>
Public Class Marks2
    Inherits List(Of Integer)
End Class

이 경우 Marks1 의 인스턴스는 testMarks에 할당될 수 있습니다. 그러나 데이터 계약이 Marks2 데이터 계약과 동일하지 않으므로 IList<int> 를 사용해서는 안 됩니다. 데이터 계약 이름은 "ArrayOfint"가 아닌 "Marks2"이며 반복되는 요소 이름은 "<int>"가 아닌 "<mark>"입니다.

다음 표의 규칙은 컬렉션의 다형적 할당에 적용됩니다.

선언된 형식 사용자 지정되지 않은 컬렉션 할당 사용자 지정된 컬렉션 할당
Object 계약 이름이 serialize되어 있습니다. 계약 이름이 serialize되어 있습니다.

사용자 지정이 사용됩니다.
컬렉션 인터페이스 계약 이름이 serialize되어 있지 않습니다. 계약 이름이 serialize되어 있지 않습니다.

사용자 지정이 사용되지 않습니다.*
사용자 지정되지 않은 컬렉션 계약 이름이 serialize되어 있지 않습니다. 계약 이름이 serialize되어 있습니다.

사용자 지정이 사용됩니다.**
사용자 지정된 컬렉션 계약 이름이 serialize되어 있습니다. 사용자 지정이 사용되지 않습니다.** 계약 이름이 serialize되어 있습니다.

할당된 형식의 사용자 지정이 사용됩니다.**

*이 경우 NetDataContractSerializer 클래스와 함께 사용자 지정이 사용됩니다. 또한 NetDataContractSerializer 클래스는 이 경우의 실제 형식 이름을 serialize하므로 deserialization이 예상대로 작동합니다.

**이러한 경우 스키마에 맞지 않는 인스턴스가 발생하므로 사용하지 마십시오.

계약 이름이 serialize된 경우에는 할당된 컬렉션 형식이 알려진 형식 목록에 있어야 합니다. 반대의 경우도 마찬가지입니다. 이름이 serialize되지 않은 경우에는 형식을 알려진 형식 목록에 추가할 필요가 없습니다.

파생 형식의 배열은 기본 형식의 배열에 할당될 수 있습니다. 이 경우 파생 형식의 계약 이름이 반복되는 각 요소에 serialize됩니다. 예를 들어, Book 형식이 LibraryItem형식에서 파생되는 경우 Book 의 배열을 LibraryItem의 배열에 할당할 수 있습니다. 이는 다른 컬렉션 형식에 적용되지 않습니다. 예를 들어, Generic List of BookGeneric List of LibraryItem에 할당할 수 없습니다. 그러나 Generic List of LibraryItem 인스턴스를 포함하는 Book 을 할당할 수는 있습니다. 배열인 경우든 배열이 아닌 경우든 Book 은 알려진 형식 목록에 있어야 합니다.

컬렉션 및 개체 참조 유지

serializer가 개체 참조를 유지하는 모드에서 작동하는 경우 개체 참조 유지도 컬렉션에 적용됩니다. 특히 개체 ID는 전체 컬렉션 및 컬렉션에 포함된 개별 항목 모두에 대해 유지됩니다. 사전의 경우 개체 ID는 키/값 쌍 개체, 개별 키 개체 및 값 개체 모두에 대해 유지됩니다.

참고 항목