82 votes

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

Je cherche un objet de type paire clé/valeur que je peux inclure dans un service web.

J'ai essayé d'utiliser la fonction System.Collections.Generic.KeyValuePair<> mais elle 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 connaisse un moyen de résoudre ce problème.

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

J'utiliserais la fonction System.Web.UI.Pair mais elle utilise Object pour ses types. Ce serait bien d'utiliser une classe générique, ne serait-ce que pour la sécurité des types.

96voto

leppie Points 67289

Il suffit de définir une structure/classe.

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

3 votes

@Paddy : Savoir comment les valuetypes sont hachés et comparer l'égalité est un must.

3 votes

IDictionary est sérialisable maintenant, en 4.5 (au moins avec JSON)

0 votes

@Joe : N'hésitez pas à écrire votre propre constructeur.

22voto

Compile This Points 4684

Je ne pense pas qu'il y ait Dictionary<> lui-même n'est pas sérialisable au format XML, lorsque j'ai eu besoin d'envoyer un objet dictionnaire via un service web, j'ai fini par envelopper l'objet Dictionary<> et l'ajout de la prise en charge de l'objet 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 votes

L'OP ne mentionne pas du tout le dictionnaire. La question porte sur la sérialisation d'une paire clé/valeur. Votre réponse est liée, mais je pense qu'elle détourne de la question fondamentale.

17voto

user56931 Points 141

Vous trouverez la raison pour laquelle les KeyValuePairs ne peuvent pas être sérialisées à cet endroit. Article du blog MSDN

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

9 votes

Notez que le DataContractSerializer (tel qu'il est fourni avec .NET 3.0 et WCF) peut parfaitement gérer les KeyValuePair<,>. Il ne s'agit donc pas d'un problème général de sérialisation, mais plutôt d'un problème lié au sérialiseur spécifique que vous utilisez (comme le suggère le lien vers la page MSDN).

0 votes

Votre billet de blog MSDN ( blogs.msdn.microsoft.com/seshadripv/archive/2005/11/02/ ) est maintenant un lien mort

8voto

GregoryBrad Points 54
 [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; }

    }

2voto

Peter Oehlert Points 6351

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

17 votes

Bien que les types Tuple soient sérialisables, ils ne sont malheureusement pas sérialisables XML.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X