Is there a covariant interface for a Dictionary? [duplicate] - c#

I'm trying to expose a read-only dictionary that holds objects with a read-only interface. Internally, the dictionary is write-able, and so are the objects within (see below example code). My problem is that IReadOnlyDictionary doesn't support covariant conversions because of the reason outlined in the question here. This means I can't just expose my internal dictionary as a read only one.
So my question is, is there an efficient way to convert my internal dictionary to an IReadOnlyDictionary, or some other way to handle this? The options I can think of are:
Hold two internal dictionaries and keep them in sync.
Create a new dictionary when the property is accessed and cast all the objects within.
Cast the IReadOnly's back to NotReadOnly when using it internally.
1 seems like a pain, 2 seems highly inefficient. 3 sounds like the most promising at the moment, but is still ugly. Do I have any other options?
public class ExposesReadOnly
{
private Dictionary<int, NotReadOnly> InternalDict { get; set; }
public IReadOnlyDictionary<int, IReadOnly> PublicList
{
get
{
// This doesn't work...
return this.InternalDict;
}
}
// This class can be modified internally, but I don't want
// to expose this functionality.
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
}
public interface IReadOnly
{
string Name { get; }
}

You could write your own read-only wrapper for the dictionary, e.g.:
public class ReadOnlyDictionaryWrapper<TKey, TValue, TReadOnlyValue> : IReadOnlyDictionary<TKey, TReadOnlyValue> where TValue : TReadOnlyValue
{
private IDictionary<TKey, TValue> _dictionary;
public ReadOnlyDictionaryWrapper(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null) throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }
public IEnumerable<TKey> Keys { get { return _dictionary.Keys; } }
public bool TryGetValue(TKey key, out TReadOnlyValue value)
{
TValue v;
var result = _dictionary.TryGetValue(key, out v);
value = v;
return result;
}
public IEnumerable<TReadOnlyValue> Values { get { return _dictionary.Values.Cast<TReadOnlyValue>(); } }
public TReadOnlyValue this[TKey key] { get { return _dictionary[key]; } }
public int Count { get { return _dictionary.Count; } }
public IEnumerator<KeyValuePair<TKey, TReadOnlyValue>> GetEnumerator()
{
return _dictionary
.Select(x => new KeyValuePair<TKey, TReadOnlyValue>(x.Key, x.Value))
.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}

I would suggest that you might want to define your own covariant interfaces, and include covariant access methods as well as a method which will create a read-only wrapper object which implements either IDictionary or IReadonlyDictionary with the desired types. Simply ignore IEnumerable<KeyValuePair<TKey,TValue>> within your interface.
Depending upon what you're doing, it may be helpful to define an IFetchByKey<out TValue> which is inherited by IFetchByKey<in TKey, out TValue>, with the former accepting queries for any type of object (given an object instance, a collection of Cat should be able to say whether it contains that instance, even if it's a type Dog or ToyotaPrius; the collection won't contain any instances of the latter types, and should be able to say so).

Maybe this solutions works for you:
public class ExposesReadOnly
{
private IDictionary<int, IReadOnly> InternalDict { get; set; }
public IReadOnlyDictionary<int, IReadOnly> PublicList
{
get
{
IReadOnlyDictionary<int, IReadOnly> dictionary = new ReadOnlyDictionary<int, IReadOnly>(InternalDict);
return dictionary;
}
}
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
public void AddSomeValue()
{
InternalDict = new Dictionary<int, NotReadOnly>();
InternalDict.Add(1, new NotReadOnly() { Name = "SomeValue" });
}
}
public interface IReadOnly
{
string Name { get; }
}
class Program
{
static void Main(string[] args)
{
ExposesReadOnly exposesReadOnly = new ExposesReadOnly();
exposesReadOnly.AddSomeValue();
Console.WriteLine(exposesReadOnly.PublicList[1].Name);
Console.ReadLine();
exposesReadOnly.PublicList[1].Name = "This is not possible!";
}
}
Hope this helps!
Greets

Depending on your use case, you might be able to get away with exposing a Func<int,IReadOnly>.
public class ExposesReadOnly
{
private Dictionary<int, NotReadOnly> InternalDict { get; set; }
public Func<int,IReadOnly> PublicDictionaryAccess
{
get
{
return (x)=>this.InternalDict[x];
}
}
// This class can be modified internally, but I don't want
// to expose this functionality.
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
}
public interface IReadOnly
{
string Name { get; }
}

Another approach for a specific lack of covariance:
A work around for a specific type of useful covariance on idictionary
public static class DictionaryExtensions
{
public static IReadOnlyDictionary<TKey, IEnumerable<TValue>> ToReadOnlyDictionary<TKey, TValue>(
this IDictionary<TKey, List<TValue>> toWrap)
{
var intermediate = toWrap.ToDictionary(a => a.Key, a =>a.Value!=null? a.Value.ToArray().AsEnumerable():null);
var wrapper = new ReadOnlyDictionary<TKey, IEnumerable<TValue>>(intermediate);
return wrapper;
}
}

Related

How to cast Dictionary<T, List<T>> to IReadOnlyDictionary<T, IEnumerable<T>>? [duplicate]

I'm trying to expose a read-only dictionary that holds objects with a read-only interface. Internally, the dictionary is write-able, and so are the objects within (see below example code). My problem is that IReadOnlyDictionary doesn't support covariant conversions because of the reason outlined in the question here. This means I can't just expose my internal dictionary as a read only one.
So my question is, is there an efficient way to convert my internal dictionary to an IReadOnlyDictionary, or some other way to handle this? The options I can think of are:
Hold two internal dictionaries and keep them in sync.
Create a new dictionary when the property is accessed and cast all the objects within.
Cast the IReadOnly's back to NotReadOnly when using it internally.
1 seems like a pain, 2 seems highly inefficient. 3 sounds like the most promising at the moment, but is still ugly. Do I have any other options?
public class ExposesReadOnly
{
private Dictionary<int, NotReadOnly> InternalDict { get; set; }
public IReadOnlyDictionary<int, IReadOnly> PublicList
{
get
{
// This doesn't work...
return this.InternalDict;
}
}
// This class can be modified internally, but I don't want
// to expose this functionality.
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
}
public interface IReadOnly
{
string Name { get; }
}
You could write your own read-only wrapper for the dictionary, e.g.:
public class ReadOnlyDictionaryWrapper<TKey, TValue, TReadOnlyValue> : IReadOnlyDictionary<TKey, TReadOnlyValue> where TValue : TReadOnlyValue
{
private IDictionary<TKey, TValue> _dictionary;
public ReadOnlyDictionaryWrapper(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null) throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }
public IEnumerable<TKey> Keys { get { return _dictionary.Keys; } }
public bool TryGetValue(TKey key, out TReadOnlyValue value)
{
TValue v;
var result = _dictionary.TryGetValue(key, out v);
value = v;
return result;
}
public IEnumerable<TReadOnlyValue> Values { get { return _dictionary.Values.Cast<TReadOnlyValue>(); } }
public TReadOnlyValue this[TKey key] { get { return _dictionary[key]; } }
public int Count { get { return _dictionary.Count; } }
public IEnumerator<KeyValuePair<TKey, TReadOnlyValue>> GetEnumerator()
{
return _dictionary
.Select(x => new KeyValuePair<TKey, TReadOnlyValue>(x.Key, x.Value))
.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
I would suggest that you might want to define your own covariant interfaces, and include covariant access methods as well as a method which will create a read-only wrapper object which implements either IDictionary or IReadonlyDictionary with the desired types. Simply ignore IEnumerable<KeyValuePair<TKey,TValue>> within your interface.
Depending upon what you're doing, it may be helpful to define an IFetchByKey<out TValue> which is inherited by IFetchByKey<in TKey, out TValue>, with the former accepting queries for any type of object (given an object instance, a collection of Cat should be able to say whether it contains that instance, even if it's a type Dog or ToyotaPrius; the collection won't contain any instances of the latter types, and should be able to say so).
Maybe this solutions works for you:
public class ExposesReadOnly
{
private IDictionary<int, IReadOnly> InternalDict { get; set; }
public IReadOnlyDictionary<int, IReadOnly> PublicList
{
get
{
IReadOnlyDictionary<int, IReadOnly> dictionary = new ReadOnlyDictionary<int, IReadOnly>(InternalDict);
return dictionary;
}
}
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
public void AddSomeValue()
{
InternalDict = new Dictionary<int, NotReadOnly>();
InternalDict.Add(1, new NotReadOnly() { Name = "SomeValue" });
}
}
public interface IReadOnly
{
string Name { get; }
}
class Program
{
static void Main(string[] args)
{
ExposesReadOnly exposesReadOnly = new ExposesReadOnly();
exposesReadOnly.AddSomeValue();
Console.WriteLine(exposesReadOnly.PublicList[1].Name);
Console.ReadLine();
exposesReadOnly.PublicList[1].Name = "This is not possible!";
}
}
Hope this helps!
Greets
Depending on your use case, you might be able to get away with exposing a Func<int,IReadOnly>.
public class ExposesReadOnly
{
private Dictionary<int, NotReadOnly> InternalDict { get; set; }
public Func<int,IReadOnly> PublicDictionaryAccess
{
get
{
return (x)=>this.InternalDict[x];
}
}
// This class can be modified internally, but I don't want
// to expose this functionality.
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
}
public interface IReadOnly
{
string Name { get; }
}
Another approach for a specific lack of covariance:
A work around for a specific type of useful covariance on idictionary
public static class DictionaryExtensions
{
public static IReadOnlyDictionary<TKey, IEnumerable<TValue>> ToReadOnlyDictionary<TKey, TValue>(
this IDictionary<TKey, List<TValue>> toWrap)
{
var intermediate = toWrap.ToDictionary(a => a.Key, a =>a.Value!=null? a.Value.ToArray().AsEnumerable():null);
var wrapper = new ReadOnlyDictionary<TKey, IEnumerable<TValue>>(intermediate);
return wrapper;
}
}

Interface To Generic Casting issue

I'm implementing a custom data store against an in memory state tree and I'm running into some issues with my indexing. My indexes are meant to be covering, so they should return the object not just a position. An index has a name, and a List of objects. Those objects can be different underlying types so the indexed objects are IHasUUID which indicates an item has a UUID.
public class DataIndex
{
public string Name;
public IDictionary<string, List<IHasUUID>> Index;
}
public class Indexer
{
private List<DataIndex> Indexes;
...
public List<IHasUUID> GetIndexedItems(List<IHasUUID> indexBy)
{
var indexer = GetIndexByKeys<IHasUUID>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<IHasUUID>(indexer, indexHash);
}
private List<T> GetIndexValues<T>(DataIndex indexBy, string indexHash) where T : IHasUUID
{
if (indexBy == null)
return new List<T>();
return ((IList<T>)indexBy.Index[indexHash]).ToList();
}
}
I generate the key to the dictionary using a reflection method where I look at the things being used as the index key and append the type string names
So I ask my Engine to FindRecords, no problem
public List<T> FindRecords<T>(IHasUUID indexBy) where T : IHasUUID
{
var indexedIds = Indexer.GetIndexedItems(new List<IHasUUID>() { indexBy });
return ((IList<T>)indexedIds).ToList();
}
Here I run into a wall on the FindRecords return
I have
return ((IList<T>)indexedIds).ToList();
and I tried
return indexedIds.ToList();
Neither one is able to cast up to T. Is this possible?
Thanks in advance
EDIT
I do seem to be much closer,
public class DataIndex
{
public DataIndex()
{
Index = new Dictionary<string, IEnumerable<IHasUUID>>();
}
public string Name;
public Dictionary<string, IEnumerable<IHasUUID>> Index;
}
public class Indexer
{
private List<DataIndex> Indexes;
public Indexer()
{
Indexes = new List<DataIndex>();
}
public IEnumerable<T> GetIndexedItems<T>(IEnumerable<IHasUUID> indexBy) where T : IHasUUID
{
var indexer = GetIndexByKeys<T>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<T>(indexer, indexHash);
}
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string indexHash) where T : IHasUUID
{
if (dataIndex == null)
return new List<T>();
return dataIndex.Index[indexHash].ToList() as List<T>;
}
}
However I am getting null back from GetIndexValues. I also tried returning it as an IEnumerable, also null
Here's my Add to index method
public void AddManyToIndex<T>(IEnumerable<IHasUUID> keys, IEnumerable<IHasUUID> newItems) where T : IHasUUID
{
var index = GetIndexByKeys<T>(keys) ?? CreateIndex<T>(keys);
string indexKey = GetHashKey(keys);
if (!index.Index.ContainsKey(indexKey))
{
index.Index[indexKey] = new List<IHasUUID>();
}
var list = index.Index[indexKey].ToList();
list.AddRange(newItems.ToList());
index.Index[indexKey] = list as IEnumerable<IHasUUID>;
}
System.Collections.Generic.List<T> is not covariant. That is to say that, given two types T and U where a U is a T, a List<U> is not a List<T>.
This is why the cast fails, a list of a type implementing IHasUUID, T in your example, is not a List<IHasUUID>.
There are however, covariant1 generic types, such as System.Collections.Generic.IEnumerable<T> and System.Collections.Generic.IReadOnlyList<T>. For such types, given two types T and U where a U is a T, an IEnumerable<U> is an IEnumerable<T>.
In addition to solving your specific problem, using such types will also serve to make your APIs more flexible while at the same time making your implementation simpler and easier.
Consider the following:
public interface IHasUuid
{
Guid Uuid { get; }
}
public class DataIndex
{
public string Name { get; set; }
public IDictionary<string, IEnumerable<IHasUuid>> Index { get; } = new Dictionary<string, IEnumerable<IHasUuid>>();
}
public class Indexer
{
public IEnumerable<IHasUuid> GetIndexedItems(IEnumerable<IHasUuid> indexBy)
{
var indexer = GetIndexByKeys<IHasUuid>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<IHasUuid>(indexer, indexHash);
}
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string hash) where T : IHasUuid
{
if (dataIndex == null)
return Enumerable.Empty<T>();
return dataIndex.Index[hash] as IEnumerable<T>;
}
}
You can store any type that implements IEnumerable<IHasUuid> in DataIndex.Index. All generic collections in .NET implement this interface, including List<T>, HashSet<T>, ConcurrentQueue<T> and countless more.
If you wish to retain the defensive copying in the orginal code, which may well be wise, simply add the .ToWhatever() back to the code.
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string hash) where T : IHasUuid
{
if (dataIndex == null)
return Enumerable.Empty<T>();
return (dataIndex.Index[hash] as IEnumerable<T>).ToHashSet();
}
For example, you can build up a DataIndex instance like this
class Person: IHasUuid {
public Guid Uuid { get; }
public string Name { get; }
}
var index = new DataIndex {
Index = {
["People"] = new List<Person>()
}
};
var indexer = new Indexer();
var people = indexer.GetIndexValues(index, "People");
Here's a working fiddle: https://dotnetfiddle.net/qgjXR7
1: A type is covariant over its type parameter if that type parameter is declared using the out modifier. As its name suggests, the out modifier means that type parameter to which it is ascribed may only be used in output positions in the declaring type.
interface Wrapper<out T>
{
T Value { get; } // OK
T Value { get; set; } // Error
void SetValue(T value); // Error
}
Interface and delegate types can declare covariant type parameters, concrete types such as classes and structs may not.

Serialize Dictionary<string,string> member to XML elements and data

I have a class 'products' that is serializable to XML. I'm using the standard System.Xml.Serialization.XmlSerializer to serialize and a XmlWriter 'writer' object to write the serialized results to a StreamWriter object. The serializer object now serializes the whole class in one go:
XmlSerializer serializer = new XmlSerializer(typeof(products));
serializer.Serialize(writer, products);
The class has a Dictionary<string,string> member called 'Specifications'. It is dynamically built, so I don't know the keys beforehand. Here's an example of what data the dictionary may contain (key: value):
color: blue
length: 110mm
width: 55mm
I would like to be able to serialize that property into this:
...
<specifications>
<color>blue</color>
<length>110mm</length>
<width>55mm</width>
</specifications>
...
I know this is poor XML design, but it has to conform to a 3rd party specification.
Is there perhaps a standard attribute that I can use? If not, how would I be able to serialize the dictionary like that?
If you need more code snippets, let me know.
EDIT:
Due to some changes in requirement, I let go of the Dictionary<string,string>. Instead, I created a class "Specification":
public class Specification
{
public string Name;
public string Value;
public bool IsOther;
public Specification() : this(null, null, false) { }
public Specification(string name, string value) : this(name, value, false) { }
public Specification(string name, string value, bool isOther)
{
Name = name;
Value = value;
IsOther = isOther;
}
}
To avoid repeating the element "spec" by having a List of "Specification" in the product class, I use a plural class "Specifications" that implements the IXmlSerializable interface:
public class Specifications: IXmlSerializable
{
public List<Specification> Specs = new List<Specification>();
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
//I don't need deserialization, but it would be simple enough now.
throw new System.NotImplementedException();
}
public void WriteXml(XmlWriter writer)
{
//write all "standarad", named specs
//this writes the <color>blue</color>-like elements
Specs.Where(s => !s.IsOther).ToList().ForEach(s => writer.WriteElementString(s.Name, s.Value));
//write other specs
//this writes <other_specs>{name|value[;]}*</other_specs>
string otherSpecs = string.Join(";", Specs.Where(s => s.IsOther).Select(s => string.Concat(s.Name, "|", s.Value)));
if (otherSpecs.Length > 0) writer.WriteElementString("other_specs", otherSpecs);
}
}
The class "Specifications" is applied as:
public class Product
{
public Product()
{
Specifications = new Specifications();
}
[XmlElement("specs")]
public Specifications Specifications;
//this "feature" will not include <specs/> when there are none
[XmlIgnore]
public bool SpecificationsSpecified { get { return Specifications.Specs.Any(); } }
//...
}
Thank you for providing examples of IXmlSerializable and XmlWriter. I didn't know that interface and usage of XmlWriter - it proved to be a valuable inspiration for me!
*this was my first SO question. What's the most appropriate way to close it? I didn't provide this as my own answer as it is not a real answer to my initial question (about Dictionary).
Assuming that your dictionary value are all simple types that can be converted to a string, you can create your own IXmlSerializable dictionary wrapper to store and retrieve the keys and values:
public class XmlKeyTextValueListWrapper<TValue> : CollectionWrapper<KeyValuePair<string, TValue>>, IXmlSerializable
{
public XmlKeyTextValueListWrapper() : base(new List<KeyValuePair<string, TValue>>()) { } // For deserialization.
public XmlKeyTextValueListWrapper(ICollection<KeyValuePair<string, TValue>> baseCollection) : base(baseCollection) { }
public XmlKeyTextValueListWrapper(Func<ICollection<KeyValuePair<string, TValue>>> getCollection) : base(getCollection) {}
#region IXmlSerializable Members
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
var converter = TypeDescriptor.GetConverter(typeof(TValue));
XmlKeyValueListHelper.ReadXml(reader, this, converter);
}
public void WriteXml(XmlWriter writer)
{
var converter = TypeDescriptor.GetConverter(typeof(TValue));
XmlKeyValueListHelper.WriteXml(writer, this, converter);
}
#endregion
}
public static class XmlKeyValueListHelper
{
public static void WriteXml<T>(XmlWriter writer, ICollection<KeyValuePair<string, T>> collection, TypeConverter typeConverter)
{
foreach (var pair in collection)
{
writer.WriteStartElement(XmlConvert.EncodeName(pair.Key));
writer.WriteValue(typeConverter.ConvertToInvariantString(pair.Value));
writer.WriteEndElement();
}
}
public static void ReadXml<T>(XmlReader reader, ICollection<KeyValuePair<string, T>> collection, TypeConverter typeConverter)
{
if (reader.IsEmptyElement)
{
reader.Read();
return;
}
reader.ReadStartElement(); // Advance to the first sub element of the list element.
while (reader.NodeType == XmlNodeType.Element)
{
var key = XmlConvert.DecodeName(reader.Name);
string value;
if (reader.IsEmptyElement)
{
value = string.Empty;
// Move past the end of item element
reader.Read();
}
else
{
// Read content and move past the end of item element
value = reader.ReadElementContentAsString();
}
collection.Add(new KeyValuePair<string,T>(key, (T)typeConverter.ConvertFromInvariantString(value)));
}
// Move past the end of the list element
reader.ReadEndElement();
}
public static void CopyTo<TValue>(this XmlKeyTextValueListWrapper<TValue> collection, ICollection<KeyValuePair<string, TValue>> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
if (collection == null)
dictionary.Clear();
else
{
if (collection.IsWrapperFor(dictionary)) // For efficiency
return;
var pairs = collection.ToList();
dictionary.Clear();
foreach (var item in pairs)
dictionary.Add(item);
}
}
}
public class CollectionWrapper<T> : ICollection<T>
{
readonly Func<ICollection<T>> getCollection;
public CollectionWrapper(ICollection<T> baseCollection)
{
if (baseCollection == null)
throw new ArgumentNullException();
this.getCollection = () => baseCollection;
}
public CollectionWrapper(Func<ICollection<T>> getCollection)
{
if (getCollection == null)
throw new ArgumentNullException();
this.getCollection = getCollection;
}
public bool IsWrapperFor(ICollection<T> other)
{
if (other == Collection)
return true;
var otherWrapper = other as CollectionWrapper<T>;
return otherWrapper != null && otherWrapper.IsWrapperFor(Collection);
}
ICollection<T> Collection { get { return getCollection(); } }
#region ICollection<T> Members
public void Add(T item)
{
Collection.Add(item);
}
public void Clear()
{
Collection.Clear();
}
public bool Contains(T item)
{
return Collection.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
Collection.CopyTo(array, arrayIndex);
}
public int Count
{
get { return Collection.Count; }
}
public bool IsReadOnly
{
get { return Collection.IsReadOnly; }
}
public bool Remove(T item)
{
return Collection.Remove(item);
}
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return Collection.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
And then use it like so:
[XmlRoot("products")]
public class Products
{
public Products()
{
Specifications = new Dictionary<string, string>();
}
[XmlIgnore]
[JsonProperty("specifications")] // For testing purposes, I compare Json.NET serialization before and after XML serialization. You can remove this.
public Dictionary<string, string> Specifications { get; set; }
[XmlElement("specifications")]
[JsonIgnore] // For testing purposes, I compare Json.NET serialization before and after XML serialization. You can remove this.
public XmlKeyTextValueListWrapper<string> XmlSpecifications
{
get
{
return new XmlKeyTextValueListWrapper<string>(() => this.Specifications);
}
set
{
value.CopyTo(Specifications = (Specifications ?? new Dictionary<string, string>()));
}
}
}
The fact that your dictionary values are simple types (directly convertible from and to text) makes it possible to avoid nested creations of XmlSerializer, which is more complex. See here for an example.
Make the dictionary NonSerialized
[XmlRoot("specifications")]
public class Specifications
{
[NonSerialized]
Dictionary<string, string> dict { get; set; }
[XmlElement("color")]
string color {get;set;}
[XmlElement("length")]
string length { get; set; }
[XmlElement("width")]
string width { get; set; }
public Specifications()
{
dict = new Dictionary<string, string>();
}
}

List<> of specific class types

Say that I have a series of classes:
abstract class MyClass { }
class MyFirstClass : MyClass { }
class MySecondClass : MyClass { }
class MyThirdClass : MyClass { }
I want to do something based on a configurable list of these derived class types, so I want to store the chosen class's Types in a list. I know I could create a List<Type>, but I could theoretically add any class to that list. On the other hand, a List<MyClass> would be a list of instances of these classes, rather than a list of the types themselves. I could also create an enum with one value that corresponds to each derived type, and have a factory method to create the correct one as needed, but that's at least two more places I'd have to update when I added MyFourthClass.
Is there a way to do something like new List<typeof(MyClass)>() = new[] { typeof(MyFirstClass), typeof(MyThirdClass)}? Does the very fact I'm asking this question imply a problem with my design?
What you want is a generic list of types (List<Type>) but like you said, you can insert any type there. The solution I can give you is to implement your own List of types from MyClass, for instance:
class TypeMyClassList : IList<Type>
{
private readonly List<Type> _list = new List<Type>();
private bool CheckType(Type type)
{
return type.IsSubclassOf(typeof (MyClass)) || typeof (MyClass) == type;
}
public IEnumerator<Type> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(Type item)
{
if (CheckType(item))
_list.Add(item);
else
throw new InvalidOperationException("You can't add other types than derived from A");
}
public void Clear()
{
_list.Clear();
}
public bool Contains(Type item)
{
return _list.Contains(item);
}
public void CopyTo(Type[] array, int arrayIndex)
{
_list.CopyTo(array, arrayIndex);
}
public bool Remove(Type item)
{
return _list.Remove(item);
}
public int Count
{
get { return _list.Count; }
}
public bool IsReadOnly { get { return false; } }
public int IndexOf(Type item)
{
return _list.IndexOf(item);
}
public void Insert(int index, Type item)
{
if (!CheckType(item))
throw new InvalidOperationException("You can't insert other types than derived from A");
_list.Add(item);
}
public void RemoveAt(int index)
{
_list.RemoveAt(index);
}
public Type this[int index]
{
get
{
return _list[index];
}
set
{
Insert(index, value);
}
}
}
Then you could do thinks like this that you want:
var typeMyClassList = new TypeMyClassList
{
typeof(MyClass),
typeof(MyClassA),
typeof(MyClassB)
};
The bad thing is that it will allows to do this in compilance time (the error will be raised on runtime):
var typeMyClassList = new TypeMyClassList
{
typeof(MyClass),
typeof(MyClassA),
typeof(MyClassB),
typeof(string)
};
There's no way to do this with static, compile-time type checking. Your best bet is to go with a solution like Raul OtaƱo's in which you do your checks at runtime.
Why can't you do this? The reason is that C# lacks static metaclass types. A metaclass is the class of a class. In other words, the instances of a metaclass are themselves classes. If C# had metaclasses, you could say something like IList<MyClassMeta> (or perhaps the syntax would be IList<meta MyClass> and the compiler would only allow you to pass MyClass (or its subclasses) as "instances", e.g.,
IList<meta MyClass> list;
list.Add(MyClass);
I've been wanting this functionality for a long time, but I don't expect it any time soon.

How to reduce type declarations when using lambda parameters?

Below is a heavily cut down version of some code I have
public class DataInfo<T>
{
public DataInfo(string description, Func<T, object> funcToGetValue)
{
this.description = description;
this.funcToGetValue= funcToGetValue;
}
public readonly string description;
public readonly Func<T, object> funcToGetValue;
}
public class DataType1
{
public int fieldA { get; set; }
public string fieldB { get; set; }
}
public class CurrentUse
{
static List<DataInfo<DataType1>> data1 = new List<DataInfo<DataType1>>()
{
new DataInfo<DataType1>("someStuff", data => data.fieldA),
new DataInfo<DataType1>("someOtherStuff", data => data.fieldB)
};
}
(There are many types, and don't worry not everything is public really!)
This is working and is OK as far as it goes, but the fact that I have to keep repeating new DataInfo<DataType1> bothers me a bit.
I tried creating a non generic helper verion of DataInfo to create the objects for me as so
public class DataInfo
{
public static DataInfo<T> Create<T>(string description, Func<T, object> func)
{
return new DataInfo<T>(description, func);
}
}
public class DesiredUse
{
static List<DataInfo<DataType1>> data1 = new List<DataInfo<DataType1>>()
{
DataInfo.Create("someStuff", data => data.fieldA),
DataInfo.Create("someOtherStuff", data => data.fieldB)
};
}
But that doesn't work as it the compiler cannot resolve fieldA & fieldB as it cannot infer the type of data.
Any ideas how I can get rid of the duplicated type info? I don't mind making changes, as long as I end up with a list of DataInfos
I'd create a builder class:
public sealed class DataInfoListBuilder<T> : IEnumerable
{
private readonly List<DataInfo<T>> list = new List<DataInfo<T>>();
public void Add(string description, Func<T, object> function)
{
list.Add(DataInfo.Create<T>(description, function));
}
public List<DataInfo<T>> Build()
{
return list;
}
public IEnumerator GetEnumerator()
{
throw new InvalidOperationException
("IEnumerator only implemented for the benefit of the C# compiler");
}
}
Then use it as:
static List<DataInfo<DataType1>> data1 = new DataInfoListBuilder<DataType1>
{
{ "someStuff", data => data.fieldA },
{ "someOtherStuff", data => data.fieldB }
}.Build();
I haven't tested it, but I think that should work. You could make it a non-generic type within DataInfo, in which case you'd use:
static List<DataInfo<DataType1>> data1 = new DataInfo<DataType1>.Builder
{ ... }.Build();
You can possibly inherit from List> and provide a specialized add method:
public class SpecialList<T> : List<DataInfo<T>>
{
public void Add(string description, Func<T, object> func)
{
base.Add(new DataInfo<T>(description, func));
}
}
Then, you can use it like this:
public class CurrentUse
{
public static SpecialList<DataType1> Data1
{
get
{
SpecialList<DataType1> list = new SpecialList<DataType1>();
list.Add("someStuff", data => data.fieldA);
list.Add("someOtherStuff", data => data.fieldB);
return list;
}
}

Categories