Có lớp cặp Khóa / Giá trị chung chung có thể tuần tự hóa trong .NET không?


79

Tôi đang tìm đối tượng cặp khóa / giá trị mà tôi có thể đưa vào dịch vụ web.

Tôi đã thử sử dụng System.Collections.Generic.KeyValuePair<>lớp của .NET , nhưng nó không tuần tự hóa đúng cách trong dịch vụ web. Trong một dịch vụ web, các thuộc tính Khóa và Giá trị không được tuần tự hóa, khiến lớp này trở nên vô dụng, trừ khi ai đó biết cách khắc phục điều này.

Có bất kỳ lớp chung chung nào khác có thể được sử dụng cho tình huống này không?

Tôi muốn sử dụng System.Web.UI.Pairlớp của .NET , nhưng nó sử dụng Đối tượng cho các loại của nó. Sẽ rất tốt nếu sử dụng lớp Chung, nếu chỉ để đảm bảo an toàn cho kiểu.

Câu trả lời:


95

Chỉ cần xác định một cấu trúc / lớp.

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

3
@Paddy: Biết làm thế nào valuetypes được băm và so sánh bình đẳng là điều bắt buộc
— leppie

2
IDictionary hiện có thể được tuần tự hóa, trong 4.5 (ít nhất là với JSON)
— tomg

@Joe: Hãy thoải mái viết hàm tạo của riêng bạn.
— leppie

@leppie Tôi đã làm, nhưng chỉ là một quan sát về câu trả lời tuyệt vời này.
— Joe

Sau khi thử điều này, tôi gặp lỗi bản dựng này. Xin vui lòng cung cấp bất kỳ ý tưởng để sửa chữa. '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

Tôi không nghĩ rằng Dictionary<>bản thân nó không thể tuần tự hóa XML, khi tôi cần gửi một đối tượng từ điển qua một dịch vụ web, tôi đã Dictionary<>tự mình gói đối tượng và thêm hỗ trợ 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 hoàn toàn không đề cập đến Từ điển. Câu hỏi là về việc tuần tự hóa một cặp khóa / giá trị. Câu trả lời của bạn có liên quan, nhưng tôi nghĩ rằng nó làm mất đi vấn đề cơ bản.
— Adam Ralph

17

Bạn sẽ tìm thấy lý do tại sao KeyValuePairs không thể được đăng nhiều kỳ tại Bài đăng trên Blog MSDN này

Câu trả lời Struct là giải pháp đơn giản nhất, tuy nhiên không phải là giải pháp duy nhất. Giải pháp "tốt hơn" là viết một lớp Custom KeyValurPair có thể nối tiếp.


9
Lưu ý rằng DataContractSerializer (đi kèm với .NET 3.0 và WCF) có thể xử lý KeyValuePair <,> một cách hoàn hảo. Vì vậy, nó không phải là vấn đề tuần tự hóa chung chung, mà là vấn đề của trình tuần tự hóa cụ thể mà bạn sử dụng (như liên kết đến Trang MSDN gợi ý).
— Christian.K

Bài đăng trên Blog MSDN của bạn ( blog.msdn.microsoft.com/seshadripv/archive/2005/11/02/… ) hiện là một liên kết chết
— 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

Trong Khung công tác 4.0, cũng có sự bổ sung của họ Tuple của các lớp có thể tuần tự hóa và tương đương. Bạn có thể sử dụng Tuple.Create(a, b)hoặc new Tuple<T1, T2>(a, b).


16
Mặc dù các loại Tuple có thể Serializable, nhưng tiếc là chúng không thể Serializable XML
— Cheetah 12/02

0

KeyedCollection là một loại từ điển có thể được tuần tự hóa trực tiếp sang xml mà không có bất kỳ điều gì vô nghĩa. Vấn đề duy nhất là bạn phải truy cập các giá trị bằng: coll ["key"]. Value;


Tôi không nghĩ rằng KeyedCollection có thể được tuần tự hóa trong WebService bởi vì nó không có bất kỳ hàm tạo công khai nào. Thuộc tính [Serializable] chỉ hoạt động để xóa.
— Martin


0

Sử dụng DataContractSerializer vì nó có thể xử lý Cặp giá trị chính.

    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

DataTablelà bộ sưu tập yêu thích của tôi để (duy nhất) gói dữ liệu được tuần tự hóa thành JSON, vì nó dễ dàng mở rộng mà không cần bổ sung struct& hoạt động giống như một sự thay thế có thể tuần tự hóa choTuple<>[]

Có thể không phải là cách rõ ràng nhất, nhưng tôi thích đưa và sử dụng nó trực tiếp trong các lớp (sẽ được tuần tự hóa), thay vì khai báo một 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);
    }
}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.