Есть ли в .NET сериализуемый общий класс пары ключ / значение?

Я ищу объект пары ключ / значение, который можно включить в веб-службу.

Я пробовал использовать класс .NET System.Collections.Generic.KeyValuePair<>, но он не сериализуется должным образом в веб-службе. В веб-сервисе свойства Key и Value не сериализуются, что делает этот класс бесполезным, если кто-то не знает, как это исправить.

Есть ли какой-либо другой универсальный класс, который можно использовать в этой ситуации?

Я бы использовал класс .NET System.Web.UI.Pair, но он использует Object для своих типов. Было бы неплохо использовать класс Generic хотя бы для обеспечения безопасности типов.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
79
0
94 124
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Ответ принят как подходящий

Просто определите структуру / класс.

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

@Paddy: необходимо знать, как хешируются типы значений, и сравнивать равенство

leppie 15.03.2012 15:56

IDictionary теперь сериализуем, в версии 4.5 (по крайней мере, с JSON)

tomg 23.05.2013 13:50

@Joe: Не стесняйтесь писать свой собственный конструктор.

leppie 11.04.2014 18:55

@leppie Я сделал, но просто наблюдение за этим отличным ответом.

Joe 11.04.2014 18:58

Попробовав это, я получаю эту ошибку сборки. Пожалуйста, поделитесь своими идеями по исправлению. '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 26.08.2019 20:46

Я не думаю, что есть, поскольку 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
}

OP вообще не упоминает словарь. Вопрос в сериализации пары ключ / значение. Ваш ответ связан, но я думаю, что он отвлекает от основной проблемы.

Adam Ralph 22.03.2011 15:58

KeyedCollection - это тип словаря, который можно напрямую сериализовать в xml без всякой ерунды. Единственная проблема заключается в том, что вам нужно получить доступ к значениям с помощью: coll ["key"]. Value;

Я не думаю, что KeyedCollection можно сериализовать в Веб-сервис, потому что у него нет общедоступного конструктора. Атрибут [Serializable] работает только для удаленного взаимодействия.

Martin 18.05.2009 19:26

Вы найдете причину, по которой KeyValuePairs не могут быть сериализованы в этом Сообщение в блоге MSDN

Ответ Struct - самое простое, но не единственное решение. «Лучшее» решение - написать класс Custom KeyValurPair, который является сериализуемым.

Обратите внимание, что DataContractSerializer (поскольку он поставляется с .NET 3.0 и WCF) отлично справляется с KeyValuePair <,>. Таким образом, это не общая проблема сериализации, а проблема конкретного сериализатора, который вы используете (как следует из ссылки на страницу MSDN).

Christian.K 20.01.2009 08:59

Ваше сообщение в блоге MSDN (blogs.msdn.microsoft.com/seshadripv/archive/2005/11/02/…) теперь неактивная ссылка

brewmanz 10.04.2019 00:19

В 4.0 Framework также добавлено семейство классов Tuple, которые можно сериализовать и уравнять. Вы можете использовать Tuple.Create(a, b) или new Tuple<T1, T2>(a, b).

Хотя типы Tuple являются сериализуемыми, они, к сожалению, не поддерживают сериализацию XML.

Cheetah 13.02.2011 02:32

Вы можете использовать Tuple<string,object>

см. здесь для получения дополнительной информации об использовании Tuple: Работа с кортежем в C# 4.0

Это был уже предложил. К сожалению, класс Tuple не поддерживает сериализацию XML.

Dan Herbert 04.11.2011 17:19

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

    }

XmlSerializer не работает со словарями. О, и у него тоже проблемы с KeyValuePairs

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

Используйте 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();
        }
    }

DataTable - моя любимая коллекция для (исключительно) упаковки данных для сериализации в JSON, поскольку ее легко расширить без необходимости в дополнительном 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);
    }
}

Другие вопросы по теме