Szukam obiektu pary klucz / wartość, który mogę dołączyć do usługi internetowej.
Próbowałem użyć System.Collections.Generic.KeyValuePair<>
klasy .NET , ale nie jest ona poprawnie serializowana w usłudze sieciowej. W usłudze sieci Web właściwości klucza i wartości nie są serializowane, co sprawia, że ta klasa jest bezużyteczna, chyba że ktoś zna sposób, aby to naprawić.
Czy istnieje inna klasa ogólna, której można użyć w tej sytuacji?
Użyłbym System.Web.UI.Pair
klasy .NET , ale używa ona Object dla swoich typów. Byłoby miło użyć klasy Generic, choćby ze względu na bezpieczeństwo typów.
'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>>'
Wydaje mi się, że nie ma, ponieważ
Dictionary<>
sam w sobie nie jest możliwy do serializacji XML, kiedy musiałem wysłać obiekt słownika za pośrednictwem usługi sieciowej, w końcu sam zawinąłemDictionary<>
obiekt i dodałem obsługę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 }
źródło
W tym poście na blogu MSDN znajdziesz powód, dla którego nie można serializować par kluczy KeyValuePairs
Odpowiedź Struct jest najprostszym rozwiązaniem, ale nie jedynym rozwiązaniem. „Lepszym” rozwiązaniem jest napisanie klasy Custom KeyValurPair z możliwością serializacji.
źródło
[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; } }
źródło
W ramach 4.0 Framework jest również dodana rodzina klas Tuple, które można serializować i wyrównywać. Możesz użyć
Tuple.Create(a, b)
lubnew Tuple<T1, T2>(a, b)
.źródło
KeyedCollection to typ słownika, który można bezpośrednio serializować do XML bez żadnych bzdur. Jedynym problemem jest to, że musisz uzyskać dostęp do wartości przez: coll ["klucz"]. Wartość;
źródło
XmlSerializer nie działa ze słownikami. Aha, i ma też problemy z KeyValuePairs
http://www.codeproject.com/Tips/314447/XmlSerializer-doesnt-work-with-Dictionaries-Oh-and
źródło
Użyj DataContractSerializer, ponieważ może obsługiwać parę klucz-wartość.
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(); } }
źródło
DataTable
jest moją ulubioną kolekcją do (wyłącznie) opakowywania danych, które mają być serializowane do formatu JSON, ponieważ można je łatwo rozszerzyć bez potrzeby dodatkowegostruct
i działa jak serializowalny zamiennik dlaTuple<>[]
Może nie jest to najczystszy sposób, ale wolę włączać i używać go bezpośrednio w klasach (które mają być serializowane), zamiast deklarować nowy
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); } }
źródło
Możesz użyć
Tuple<string,object>
zobacz to, aby uzyskać więcej informacji na temat
Tuple
użycia: Praca z krotką w C # 4.0źródło