web-dev-qa-db-fra.com

Existe-t-il une classe de paires clé/valeur générique sérialisable dans .NET?

Je recherche un objet paire clé/valeur que je puisse inclure dans un service Web.

J'ai essayé d'utiliser System.Collections.Generic.KeyValuePair<> class .NET, mais cela ne se sérialise pas correctement dans un service Web. Dans un service Web, les propriétés Key et Value ne sont pas sérialisées, ce qui rend cette classe inutile, à moins que quelqu'un ne sache comment résoudre ce problème.

Existe-t-il une autre classe générique pouvant être utilisée dans cette situation?

J'utiliserais le System.Web.UI.Pair class de .NET, mais il utilisera Object pour ses types. Il serait bien d’utiliser une classe générique, ne serait-ce que pour la sécurité du type.

74
Dan Herbert

Il suffit de définir une structure/classe.

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

Je ne pense pas que Dictionary<> lui-même ne soit pas sérialisable en XML, alors que j'avais besoin d'envoyer un objet dictionnaire via un service Web, j'ai fini par emballer moi-même l'objet Dictionary<> et d'ajouter le support de 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
}
22
Compile This

Vous trouverez la raison pour laquelle KeyValuePairs ne peut pas être sérialisé à cet emplacement Blog de blog MSDN

La réponse Struct est la solution la plus simple, mais pas la seule. Une "meilleure" solution consiste à écrire une classe KeyValurPair personnalisée, qui est sérialisable.

17
user56931
 [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; }

    }
5
GregoryBrad

Dans le Framework 4.0, il y a aussi l'ajout de la famille Tuple de classes sérialisables et équalisables. Vous pouvez utiliser Tuple.Create(a, b) ou new Tuple<T1, T2>(a, b).

1
Peter Oehlert

Utilisez DataContractSerializer car il peut gérer la paire clé-valeur.

    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
Hasse

KeyedCollection est un type de dictionnaire pouvant être sérialisé directement au format XML sans aucun sens. Le seul problème est que vous devez accéder aux valeurs par: coll ["key"]. Value;

0
Will

DataTable est ma collection préférée pour l'encapsulation (uniquement) de données en série au format JSON, car il est facile de l'étendre sans avoir besoin d'une struct supplémentaire et agit comme un remplacement sérialisable de Tuple<>[]

Peut-être pas la façon la plus propre, mais je préfère l'inclure et l'utiliser directement dans les classes (qui doivent être sérialisées), au lieu de déclarer une nouvelle 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);
    }
}
0
Teodor Tite

XmlSerializer ne fonctionne pas avec les dictionnaires. Oh, et il a aussi des problèmes avec KeyValuePairs

http://www.codeproject.com/Tips/314447/XmlSerializer-doesnt-work-with-Dictionaries-Oh-and

0
Akodo_Shado