.NET에 직렬화 가능한 일반 키 / 값 쌍 클래스가 있습니까?


79

웹 서비스에 포함 할 수있는 키 / 값 쌍 개체를 찾고 있습니다.

.NET의 System.Collections.Generic.KeyValuePair<>클래스를 사용해 보았지만 웹 서비스에서 제대로 직렬화되지 않습니다. 웹 서비스에서 Key 및 Value 속성은 직렬화되지 않으므로 누군가이 문제를 해결하는 방법을 알지 않는 한이 클래스를 쓸모 없게 만듭니다.

이 상황에 사용할 수있는 다른 일반 클래스가 있습니까?

.NET의 System.Web.UI.Pair클래스를 사용하지만 유형에 대해 Object를 사용합니다. 타입 안전성을 위해서만 Generic 클래스를 사용하는 것이 좋습니다.

답변:


95

구조체 / 클래스를 정의하기 만하면됩니다.

[Serializable]
public struct KeyValuePair<K,V>
{
  public K Key {get;set;}
  public V Value {get;set;}
}

3
@Paddy : value 형이 해시됩니다 방법을 아는와 평등을 비교하는 것은 필수입니다
leppie

2
IDictionary는 이제 4.5에서 직렬화 가능합니다 (적어도 JSON 사용)
tomg

@Joe : 자유롭게 생성자를 작성하세요.
leppie 2014

@leppie 나는했지만이 다른 훌륭한 대답에 대한 관찰입니다.
Joe

이것을 시도한 후이 빌드 오류가 발생합니다. 수정할 아이디어를 제공해주세요. 'AttributeCollection' does not contain a definition for 'Where' and the best extension method overload 'Queryable.Where<KeyValuePair<string, object>>(IQueryable<KeyValuePair<string, object>>, Expression<Func<KeyValuePair<string, object>, bool>>)' requires a receiver of type 'IQueryable<KeyValuePair<string, object>>'
Karthik

22

나는이 없다고 생각 Dictionary<>자체가 XML의 직렬화 할 수없는 나는 내가 포장 결국 웹 서비스를 통해 사전 개체를 보낼 필요했을 때, Dictionary<>객체에게 자신과에 대한 지원을 추가 IXMLSerializable.

/// <summary>
/// Represents an XML serializable collection of keys and values.
/// </summary>
/// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
/// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
    #region Constants

    /// <summary>
    /// The default XML tag name for an item.
    /// </summary>
    private const string DEFAULT_ITEM_TAG = "Item";

    /// <summary>
    /// The default XML tag name for a key.
    /// </summary>
    private const string DEFAULT_KEY_TAG = "Key";

    /// <summary>
    /// The default XML tag name for a value.
    /// </summary>
    private const string DEFAULT_VALUE_TAG = "Value";

    #endregion

    #region Protected Properties

    /// <summary>
    /// Gets the XML tag name for an item.
    /// </summary>
    protected virtual string ItemTagName
    {
        get
        {
            return DEFAULT_ITEM_TAG;
        }
    }

    /// <summary>
    /// Gets the XML tag name for a key.
    /// </summary>
    protected virtual string KeyTagName
    {
        get
        {
            return DEFAULT_KEY_TAG;
        }
    }

    /// <summary>
    /// Gets the XML tag name for a value.
    /// </summary>
    protected virtual string ValueTagName
    {
        get
        {
            return DEFAULT_VALUE_TAG;
        }
    }

    #endregion

    #region Public Methods

    /// <summary>
    /// Gets the XML schema for the XML serialization.
    /// </summary>
    /// <returns>An XML schema for the serialized object.</returns>
    public XmlSchema GetSchema()
    {
        return null;
    }

    /// <summary>
    /// Deserializes the object from XML.
    /// </summary>
    /// <param name="reader">The XML representation of the object.</param>
    public void ReadXml(XmlReader reader)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        bool wasEmpty = reader.IsEmptyElement;

        reader.Read();

        if (wasEmpty)
        {
            return;
        }

        while (reader.NodeType != XmlNodeType.EndElement)
        {
            reader.ReadStartElement(ItemTagName);

            reader.ReadStartElement(KeyTagName);
            TKey key = (TKey)keySerializer.Deserialize(reader);
            reader.ReadEndElement();

            reader.ReadStartElement(ValueTagName);
            TValue value = (TValue)valueSerializer.Deserialize(reader);
            reader.ReadEndElement();

            this.Add(key, value);

            reader.ReadEndElement();
            reader.MoveToContent();
        }

        reader.ReadEndElement();
    }

    /// <summary>
    /// Serializes this instance to XML.
    /// </summary>
    /// <param name="writer">The writer to serialize to.</param>
    public void WriteXml(XmlWriter writer)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        foreach (TKey key in this.Keys)
        {
            writer.WriteStartElement(ItemTagName);

            writer.WriteStartElement(KeyTagName);
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();

            writer.WriteStartElement(ValueTagName);
            TValue value = this[key];
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
    }

    #endregion
}

5
OP는 사전을 전혀 언급하지 않습니다. 문제는 키 / 값 쌍을 직렬화하는 것입니다. 귀하의 답변은 관련이 있지만 근본적인 문제를 손상시키는 것 같습니다.
Adam Ralph

17

MSDN 블로그 게시물 에서 KeyValuePairs를 직렬화 할 수없는 이유를 확인할 수 있습니다.

Struct 대답은 가장 간단한 해결책이지만 유일한 해결책은 아닙니다. "더 나은"솔루션은 Serializable 인 Custom KeyValurPair 클래스를 작성하는 것입니다.


9
DataContractSerializer (.NET 3.0 및 WCF와 함께 제공됨)는 KeyValuePair <,>를 완벽하게 처리 할 수 ​​있습니다. 따라서 일반적인 직렬화 문제가 아니라 사용하는 특정 직렬화 문제 (MSDN 페이지 링크가 제안하는대로)의 문제입니다.
Christian.K

귀하의 MSDN 블로그 포스트 ( blogs.msdn.microsoft.com/seshadripv/archive/2005/11/02/...는 ) 이제 죽은 링크입니다
brewmanz

7
 [Serializable]
 public class SerializableKeyValuePair<TKey, TValue>
    {

        public SerializableKeyValuePair()
        {
        }

        public SerializableKeyValuePair(TKey key, TValue value)
        {
            Key = key;
            Value = value;
        }

        public TKey Key { get; set; }
        public TValue Value { get; set; }

    }

1

4.0 Framework에는 직렬화 가능하고 동등하게 사용할 수있는 Tuple 클래스 클래스가 추가되었습니다. 당신은 사용할 수 있습니다 Tuple.Create(a, b)또는 new Tuple<T1, T2>(a, b).


16
튜플 유형은 직렬화 있지만, 그들은 불행히도 XML 직렬화있다
치타

0

KeyedCollection은 말도 안되는 일없이 xml로 직접 직렬화 할 수있는 사전 유형입니다. 유일한 문제는 다음과 같이 값에 액세스해야한다는 것입니다. coll [ "key"]. Value;


KeyedCollection은 공개 생성자가 없기 때문에 WebService 내에서 직렬화 될 수 있다고 생각 하지 않습니다. [Serializable] 속성은 원격에서만 작동합니다.
Martin


0

키 값 쌍을 처리 할 수 ​​있으므로 DataContractSerializer를 사용하십시오.

    public static string GetXMLStringFromDataContract(object contractEntity)
    {
        using (System.IO.MemoryStream writer = new System.IO.MemoryStream())
        {
            var dataContractSerializer = new DataContractSerializer(contractEntity.GetType());
            dataContractSerializer.WriteObject(writer, contractEntity);
            writer.Position = 0;
            var streamReader = new System.IO.StreamReader(writer);
            return streamReader.ReadToEnd();
        }
    }

0

DataTableJSON으로 직렬화 할 데이터를 (단독으로) 래핑하는 데 가장 좋아하는 컬렉션입니다. 추가없이 확장 할 struct수 있고 직렬화 가능한 대체 역할을하기 때문입니다.Tuple<>[]

아마도 가장 깨끗한 방법은 아니지만 새로운 것을 선언하는 대신 클래스 (직렬화 될 것임)에 직접 포함하고 사용하는 것을 선호합니다. struct

class AnyClassToBeSerialized
{
    public DataTable KeyValuePairs { get; }

    public AnyClassToBeSerialized
    {
        KeyValuePairs = new DataTable();
        KeyValuePairs.Columns.Add("Key", typeof(string));
        KeyValuePairs.Columns.Add("Value", typeof(string));
    }

    public void AddEntry(string key, string value)
    {
        DataRow row = KeyValuePairs.NewRow();
        row["Key"] = key; // "Key" & "Value" used only for example
        row["Value"] = value;
        KeyValuePairs.Rows.Add(row);
    }
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.