Я ищу объект пары ключ / значение, который можно включить в веб-службу.
Я пробовал использовать класс .NET System.Collections.Generic.KeyValuePair<>, но он не сериализуется должным образом в веб-службе. В веб-сервисе свойства Key и Value не сериализуются, что делает этот класс бесполезным, если кто-то не знает, как это исправить.
Есть ли какой-либо другой универсальный класс, который можно использовать в этой ситуации?
Я бы использовал класс .NET System.Web.UI.Pair, но он использует Object для своих типов. Было бы неплохо использовать класс Generic хотя бы для обеспечения безопасности типов.





Просто определите структуру / класс.
[Serializable]
public struct KeyValuePair<K,V>
{
public K Key {get;set;}
public V Value {get;set;}
}
IDictionary теперь сериализуем, в версии 4.5 (по крайней мере, с JSON)
@Joe: Не стесняйтесь писать свой собственный конструктор.
@leppie Я сделал, но просто наблюдение за этим отличным ответом.
Попробовав это, я получаю эту ошибку сборки. Пожалуйста, поделитесь своими идеями по исправлению. '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>>'
Я не думаю, что есть, поскольку 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 вообще не упоминает словарь. Вопрос в сериализации пары ключ / значение. Ваш ответ связан, но я думаю, что он отвлекает от основной проблемы.
KeyedCollection - это тип словаря, который можно напрямую сериализовать в xml без всякой ерунды. Единственная проблема заключается в том, что вам нужно получить доступ к значениям с помощью: coll ["key"]. Value;
Я не думаю, что KeyedCollection можно сериализовать в Веб-сервис, потому что у него нет общедоступного конструктора. Атрибут [Serializable] работает только для удаленного взаимодействия.
Вы найдете причину, по которой KeyValuePairs не могут быть сериализованы в этом Сообщение в блоге MSDN
Ответ Struct - самое простое, но не единственное решение. «Лучшее» решение - написать класс Custom KeyValurPair, который является сериализуемым.
Обратите внимание, что DataContractSerializer (поскольку он поставляется с .NET 3.0 и WCF) отлично справляется с KeyValuePair <,>. Таким образом, это не общая проблема сериализации, а проблема конкретного сериализатора, который вы используете (как следует из ссылки на страницу MSDN).
Ваше сообщение в блоге MSDN (blogs.msdn.microsoft.com/seshadripv/archive/2005/11/02/…) теперь неактивная ссылка
В 4.0 Framework также добавлено семейство классов Tuple, которые можно сериализовать и уравнять. Вы можете использовать Tuple.Create(a, b) или new Tuple<T1, T2>(a, b).
Хотя типы Tuple являются сериализуемыми, они, к сожалению, не поддерживают сериализацию XML.
Вы можете использовать Tuple<string,object>
см. здесь для получения дополнительной информации об использовании Tuple: Работа с кортежем в C# 4.0
Это был уже предложил. К сожалению, класс Tuple не поддерживает сериализацию XML.
[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);
}
}
@Paddy: необходимо знать, как хешируются типы значений, и сравнивать равенство