C# object initializer wanting to use wrong Add method - c#

I have the following class hierarchy:
public class Row : ICloneable, IComparable, IEquatable<Row>,
IStringIndexable, IDictionary<string, string>,
ICollection<KeyValuePair<string, string>>,
IEnumerable<KeyValuePair<string, string>>,
System.Collections.IEnumerable
{ }
public class SpecificRow : Row, IXmlSerializable,
System.Collections.IEnumerable
{
public void Add(KeyValuePair<MyEnum, string> item) { }
}
However, trying to do the following gives an error:
var result = new SpecificRow
{
{MyEnum.Value, ""},
{MyEnum.OtherValue, ""}
};
I get this error:
The best overloaded Add method 'Row.Add(string, string)' for the collection initializer has some invalid arguments
How can I make it so that using an object initializer on the derived class SpecificRow allows type MyEnum? It seems like it should see the Add method in SpecificRow.
Update: I implemented an extra interface on SpecificRow so it now looks like this:
public class SpecificRow : Row, IXmlSerializable,
System.Collections.IEnumerable,
ICollection<KeyValuePair<MyEnum, string>>
{ }
However, I still get the same Add error. I'm going to try implementing IDictionary<MyEnum, string> next.

A collection initializer does not necessarily look at any ICollection.Add(x) method. More specifically, for a collection initializer
new SpecificRow {
{ ? }
}
C# looks at any Add method with signature Add(?); if ? contains comma's, C# looks at an Add method with multiple arguments. The compiler does not have any special handling of KeyValuePair<,> at all. The reason { string, string } works, is because your base class has an overload Add(string, string), and not because it has an overload for Add(KeyValuePair<string, string>).
So to support your syntax for
new SpecificRow {
{ MyEnum.Value, "" }
};
you need an overload of the form
void Add(MyEnum key, string value)
That's all there is to it.

It looks like it's because you're only implementing IDictionary<string, string>, and all the other interfaces associated with it. Your Add(KeyValuePair<MyEnum, string>) method isn't implementing any interface member, it's just another member of the SpecificRow class, which happens to be named Add, which is why it is getting ignored.
You should be able to do one of the following, depending on what your requirements are:
Implement IDictionary<MyEnum, string> in addition to IDictionary<MyEnum, string>, including the dependent interfaces (ICollection<KeyValuePair<MyEnum, string>>, etc).
Implement IDictionary<MyEnum, string> instead of IDictionary<MyEnum, string>, again including the dependent interfaces.
Change the declaration of Row to Row<T>, and implement IDictionary<T, string>, including the dependent interfaces. SpecificRow would then implement Row<MyEnum> instead of just Row.

Ruben's answer is definitely the best, but if you didn't want to add Add(MyEnum key, string value) then you could also initialize the collection like so:
var result = new SpecificRow
{
new KeyValuePair<MyEnum, string>(MyEnum.Value, ""}),
new KeyValuePair<MyEnum, string>(MyEnum.OtherValue, ""})
};

Related

How can I refactor this C# code currently using Dictionarys to have even less redundancy and be more typesafe?

Because of business decisions which are above my paygrade, I need to parse and merge multiple XML files.
In order to cut down on redundant code, I have this map:
private static readonly Dictionary<string, Type> listTypeByFileName = new Dictionary<string, Type> {
{"a.xml", typeof(List<A>)},
{"b.xml", typeof(List<B>)},
{"c.xml", typeof(List<C>)},
{"d.xml", typeof(List<D>)},
// etc.
};
Because how this map gets used, after downloading and parsing all the XMLs, the result is of type Dictionary<string, object> where the key is the same as the keys in the above map and the value is of the type specified in the map, as result of executing this code with DownloadFiles(config):
private static Dictionary<string, object> DownloadFiles(IConfigurationRoot config) {
Dictionary<string, object> dataListByFileNames = new Dictionary<string, object>();
listTypeByFileName.Keys.ToList()
.ForEach(name => dataListByFileNames.Add(name, DownloadData(name, config)));
return dataListByFileNames;
}
private static object DownloadData(string name, IConfigurationRoot config) {
_ = listTypeByFileName.TryGetValue(name, out Type listType);
return new XmlSerializer(listType, new XmlRootAttribute("Document"))
.Deserialize(new StringReader(DownloadFromBlobStorage(name, config).ToString()));
}
private static CloudBlockBlob DownloadFromBlobStorage(string filetoDownload, IConfigurationRoot config) {
return CloudStorageAccount.Parse(config["AzureWebJobsStorage"])
.CreateCloudBlobClient()
.GetContainerReference(config["BlobStorageContainerName"])
.GetBlockBlobReference(filetoDownload);
First question: Is there a way I can make the return more typesafe? Perhaps using parameterized types?
The second part of the problem is actually consuming this Dictionary.
For each type in this Dictionary, I now need a function like:
private void AddA(Dictionary<string, object> dataByFileNames) {
if (dataByFileNames.TryGetValue("a.xml", out object data)) {
List<A> aList = (List<A>)data;
aList.ForEach(a =>
doSomethingWithA(a);
);
}
}
private void AddB(Dictionary<string, object> dataByFileNames) {
if (dataByFileNames.TryGetValue("b.xml", out object data)) {
List<B> bList = (List<B>)data;
bList.ForEach(b =>
doSomethingWithB(b);
);
}
}
// etc.
As I already have the list of filenames to types (top of this question), I feel there should be some way to abstract the above so it does not need to be repeated again and again and again.
Note, it may be significant that every type (A, B, C, D, etc. all have a property string Id which will be definitely be needed for all doStringWithX() methods... if useful, I can create an interface to get this. It is okay if I need to caste to the correct type within each doStringWithX() or when invoking each of these methods.c
First, instead of storing the List<T> type in the dictionary, just store the underlying generic type:
private static readonly Dictionary<string, Type> listTypeByFileName = new Dictionary<string, Type> {
{"a.xml", typeof(A)},
{"b.xml", typeof(B)}
// etc.
That's going to make future steps a little bit easier. When deserializing, create the generic list type. After getting the type from the dictionary, you can do:
var listType = typeof(List<>).MakeGenericType(typeRetrievedFromDictionary);
Once you've deserialized it, cast it as IList. That's effectively casting it as a list of object. That's okay. Because you deserialized using a specific type, every item in the list will be of the expected type.
Create a dictionary for the type-safe methods you want to invoke on every time in list.
Dictionary<Type, Action<object>> methodsToInvokeByType;
Add methods to the dictionary:
doSometingMethods.Add(typeof(A), dataItem => DoSomethingWithA((A)dataItem));
doSometingMethods.Add(typeof(B), dataItem => DoSomethingWithB((B)dataItem));
Now, once you've got your IList full of objects, you retrieve the type-safe method to invoke:
var methodToInvoke = methodsToInvokeByType[typeRetrievedFromDictionary];
Then do this:
foreach(object itemInList in list) // this is your deserialized list cast as IList
{
methodToInvoke(itemInList);
}
So if the type is A, you'll be invoking
DoSomethingWithA((A)itemInList)
It's not pretty. Bridging between code that uses objects and Type and type-safe generic code can be messy. But ultimately the goal is that whatever those final methods are - DoSomethingWithA, DoSomethingWithB, etc., at least those are type-safe.
You can simplify some more:
Create a class that deserializes a list and passes it off to a method for processing, and an interface:
public interface IXmlFileProcessor
{
void Process(byte[] xmlFile);
}
public class XmlFileProcessor<T> : IXmlFileProcessor
{
private readonly Action<T> _doSomething;
public XmlFileProcessor(Action<T> doSomething)
{
_doSomething = doSomething;
}
public void Process(byte[] xmlFile) // or string or whatever
{
// deserialize into a List<T>
foreach (T item in deserializedList)
_doSomething(item);
}
}
Then create a Dictionary<Type, IXmlFileProcessor> and populate it:
fileProcessors.Add(typeof(A), new XmlFileProcessor<A>(SomeClass.DoSomethingWithA));
fileProcessors.Add(typeof(B), new XmlFileProcessor<B>(SomeClass.DoSomethingWithB));
That approach (injecting the Action) is intended to keep the "do something" method decoupled from the class responsible for deserialization. DoSomething could also be a generic method in XmlFileProcessor<T>. There are different ways to compose those classes and add them to that dictionary. But either way, having determined the type, you just retrieve the correct type-specific processor from the dictionary, pass your file to it, and it does the rest.
That approach bridges the generic/non-generic gap by making the class - XmlFileProcessor<T> - generic, but having it implement a non-generic interface. It works as long as you take steps (using the dictionary) to ensure that you're selecting the correct implementation for whatever type you're deserializing.

Extension method for dictionary with value implementing interface

I'm trying to implement an extension method for all dictionaries whose value is of a type that implement a certain interface.
In this case I would like to have a ToListSortedByValue() method that returns
List<KeyValuePair<string, IComparable>>
for any dictionary of type
Dictionary<string, IComparable>
that would be cool because it would allow me to use dictionaries instead of lists, but to be able to have them sorted when needed (for example when printing in files or at console).
This is what I tried, but it doesn't work, any idea why?
public static List<KeyValuePair<string, IComparable>> ToListSortedByValue(this Dictionary<string, IComparable> Dic)
{
return Dic.OrderBy(x => x.Value).ToList();
}
EDIT:
it's solved already, but for completeness sake this is the problem I got:
when trying to use the method I got the an error as if such method didn't exist. If instead of IComparable I use an actual comparable type, let's say int or a class implementing IComparable, than it would work.
Basically you need to make the method generic on the value type and then constrain that type to be IComparable<T>.
public static List<KeyValuePair<string, T>> ToListSortedByValue<T>(
this Dictionary<string, T> Dic) where T : IComparable<T>
{
return Dic.OrderBy(x => x.Value).ToList();
}
This has the added bonus of returning the values as there passed in type. You might even want to make the key type generic too so it's not limited to just string
public static List<KeyValuePair<TKey, TValue>> ToListSortedByValue<TKey, TValue>(
this Dictionary<TKey, TValue> Dic) where TValue : IComparable<TValue>
{
return Dic.OrderBy(x => x.Value).ToList();
}
You need to make your method generic, so that it extends your actual type instead of just IComparable:
public static List<KeyValuePair<string, T>> ToListSortedByValue<T>(this Dictionary<string, T> Dic) where T : IComparable<T>

Is there a built-in generic interface with covariant type parameter returned by an indexer?

In this thread
How to get null instead of the KeyNotFoundException accessing Dictionary value by key?
in my own answer I used explicit interface implementation to change the basic dictionary indexer behaviour not to throw KeyNotFoundException if the key was not present in the dictionary (since it was convinient for me to obtain null in such a case right inline).
Here it is:
public interface INullValueDictionary<T, U>
where U : class
{
U this[T key] { get; }
}
public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
where U : class
{
U INullValueDictionary<T, U>.this[T key]
{
get
{
if (ContainsKey(key))
return this[key];
else
return null;
}
}
}
Since in a real application I had a list of dictionaries, I needed a way to access the dictionaries from the collection as an interface. I used simple int indexer to acess each element of the list.
var list = new List<NullValueDictionary<string, string>>();
int index = 0;
//...
list[index]["somekey"] = "somevalue";
The easiest thing was to do something like this:
var idict = (INullValueDictionary<string, string>)list[index];
string value = idict["somekey"];
The question raised when I decided to try to use covariance feature to have a collection of interfaces to use instead. So I needed an interface with covariant type parameter for the cast to work. The 1st thing that came to my mind was IEnumerable<T>, so the code would look like this:
IEnumerable<INullValueDictionary<string, string>> ilist = list;
string value = ilist.ElementAt(index)["somekey"];
Not that nice at all, besides ElementAt instead of an indexer is way worse.
The indexer for List<T> is defined in IList<T>, and T there is not covariant.
What was I to do? I decided to write my own:
public interface IIndexedEnumerable<out T>
{
T this[int index] { get; }
}
public class ExtendedList<T> : List<T>, IIndexedEnumerable<T>
{
}
Well, few lines of code (I don't even need to write anything in ExtendedList<T>), and it works as I wanted:
var elist = new ExtendedList<NullValueDictionary<string, string>>();
IIndexedEnumerable<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = ielist[index]["somekey"];
Finally the question: can this covariant cast be somehow achieved without creating an extra collection?
You can try use IReadOnlyList<T>, which is implemented by List<T>.
Note that I've added one instance of NullValueDictionary<string, string> to List, so that you won't get ArgumentOutOfRangeException at elist[index] line.
IReadOnlyList<NullValueDictionary<string, string>> elist = new List<NullValueDictionary<string, string>>
{
new NullValueDictionary<string, string>()
};
IReadOnlyList<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = elist[index]["somekey"];
Edit: I've searched for covariant interfaces and collections with indexes prior to .NET 4.5, but found none. Still I think there are a little bit easier solution, than to create separate interface - just to cast one collection to another.
List<INullValueDictionary<string, string>> ielist = elist.Cast<INullValueDictionary<string, string>>().ToList();
Or use covariance gained from arrays
INullValueDictionary<string, string>[] ielist = elist.ToArray()
LINQ has some optimization that work on whole type compatibility, so you won't iterate over sequence if those types are compatible.
Cast implementation taken from MONO Linq
public static IEnumerable<TResult> Cast<TResult> (this IEnumerable source)
{
var actual = source as IEnumerable<TResult>;
if (actual != null)
return actual;
return CreateCastIterator<TResult> (source);
}
Note that I have changed INullValueDictionary<T, U> interface to contain set in the property so that ielist[index]["somekey"] = "somevalue"; will work.
public interface INullValueDictionary<T, U> where U : class
{
U this[T key] { get; set; }
}
But again - if creating a new Interface and class is ok for you and you don't want to mess around with casts everywhere - I think it is a good solution, if you have considered at the constraints, it gives.
In search of covariance in mscorlib
This probably won't be interesting to you, but I've just wanted to find out what Types are covariant in mscorlib assembly. By running next script I received only 17 types are covariant, 9 of which are Funcs. I have omitted IsCovariant implementation, because this answer is too long even without it
typeof(int).Assembly.GetTypes()
.Where(type => type.IsGenericType)
.Where(type=>type.GetGenericArguments().Any(IsCovariant))
.Select(type => type.Name)
.Dump();
//Converter`2
//IEnumerator`1
//IEnumerable`1
//IReadOnlyCollection`1
//IReadOnlyList`1
//IObservable`1
//Indexer_Get_Delegate`1
//GetEnumerator_Delegate`1

C# implement two different generic interfaces

I'm not sure what I'm wanting to do is even a good idea, but here's the problem anyway: I have MyClass which I want to implement two different types of the generic IEnumerable class, e.g.
public class MyClass : IEnumerable<KeyValuePair<string, string>>,
IEnumerable<KeyValuePair<MyEnum, string>>
Now, the problem with doing this is when I try to define necessary methods from the interfaces, the compiler complains "Type 'MyClass' already defines a member called 'GetEnumerator' with the same parameter types". This is because I have these two methods:
public IEnumerator<KeyValuePair<MyEnum, string>> GetEnumerator() { ... }
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() { ... }
I have to have GetEnumerator() with no parameters because of the interface, and the only thing that differs is the return type, which is not allowed.
Here are what I see as my options:
I was considering having a "main" IEnumerable generic type which MyClass would implement, and then just adding extra methods that differ by parameters and not just return type (e.g. Add), without implementing the extra generic interfaces.
I could create a generic base class for MyClass, call it MyBaseClass<T>, and it would implement IEnumerable<KeyValuePair<T, string>>. Then, I would have different versions of MyClass, e.g. MyClass<string> and MyClass<MyEnum>.
Which seems preferable here, or am I missing something that would be an even better solution?
You can use explicit interface declarations in order to get different implementations for each of the two interfaces that you are implement. For example:
public class MyClass : IEnumerable<KeyValuePair<string, string>>,
IEnumerable<KeyValuePair<MyEnum, string>>
{
IEnumerator<KeyValuePair<MyEnum, string>> IEnumerable<KeyValuePair<MyEnum, string>>.GetEnumerator()
{
// return your enumerator here
}
IEnumerator<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.GetEnumerator()
{
// return your enumerator here
}
IEnumerator IEnumerable.GetEnumerator()
{
var me = this as IEnumerable<KeyValuePair<string, string>>;
return me.GetEnumerator();
}
}
However, because IEnumerable<> derives from IEnumerable, you'll have to pick which one you want to return from the IEnumerable.GetEnumerator() call.
You can use explicit interface implementation to implement interfaces with conflicting methods. However, if you implement two IEnumerable<T> interfaces, it will cause some rather annoying issues for things like foreach loops. I once tried this for something and promptly went back to implementing 1 IEnumerable interface, and offering the other as a property of the object.
You can explicity implement each interface like this:
IEnumerable<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.GetEnumerator() { ... }
IEnumerator<KeyValuePair<MyEnum, string>> IEnumerator<KeyValuePair<MyEnum, string>>.GetEnumerator() { ... }
One option would be to implement interfaces explicitly.
Downside - you would always need to cast MyClass.

C# inherit from Dictionary, iterate over KeyValuePairs

I have a class that inherits from Dictionary<string, string>. Within an instance method, I want to iterate over all KeyValuePair<string, string>'s. I've tried doing the following:
foreach (KeyValuePair<string, string> pair in base)
But this fails with the following error:
Use of keyword 'base' is not valid in this context
How can I iterate over the KeyValuePair<string, string>'s in an instance method in a class that derives from Dictionary<string, string>?
Edit: I found I can do the following:
var enumerator = base.GetEnumerator();
while (enumerator.MoveNext())
{
KeyValuePair<string, string> pair = enumerator.Current;
}
However, I would still like to know if there's a way to do this via a foreach loop.
Edit: thanks for the advice about not inheriting from Dictionary<string, string>. I'm instead implementing System.Collections.IEnumerable, ICollection<KeyValuePair<string, string>>, IEnumerable<KeyValuePair<string, string>>, IDictionary<string, string>.
First, deriving from the .NET collection classes is generally ill-advised because they don't offer virtual methods for calls not inherited from object. This can result in bugs when passing your derived collection in via a base-class reference somewhere. You are better off implementing the IDictionary<T,TKey> interface and aggregating a Dictionary<,> inside your implementation - to which you then forward the appropriate calls.
That aside, in your specific case, what you want to do is:
foreach( KeyValuePair<string,string> pair in this ) { /* code here */ }
The base keyword is primarily used to access specific members of your base class. That's not what you're doing here - you are attempting to iterate over the items of a particular instance ... which is simply the this reference.
I agree with JaredPar's comment that this isn't a great idea. You probably don't want to publicly expose all of the methods of Dictionary to the outside world, so just make the Dictionary a private member variable and then provide your own interface to it.
With that said, the way to do what you're trying to do is:
foreach (KeyValuePair<string, string> pair in this)
Encapsulate Dictionary<string, string> as a composed field inside custom class MyDictionary and implement a custom IEnumerable and IEnumerator (or variations thereof) for MyDictionary (or make a method that implements handy C# yield keyword to produce the items)...
E.g.
class MyDictionary : IEnumerable<KeyValuePair<string,string>> {
Dictionary<string, string> _dict;
IEnumerator<KeyValuePair<string,string>> GetEnumerator() {
return new MyEnum(this); // use your enumerator
// OR simply forget your own implementation and
return _dict.GetEnumerator();
}
class MyEnum : IEnumerator<KeyValuePair<string,string>> {
internal MyEnum(MyDictionary dict) {
//... dict
}
// implemented methods (.MoveNext, .Reset, .Current)...
This maintains encapsulation of extraneous methods.
And you can still iterate over you instances like so from inside or outside:
// from outside
MyDictionary mdict = new MyDictionary();
foreach (KeyValuePair<string, string> kvp in mdict)
//...
// from inside, assuming: this == MyDictionary instance)
public void MyDictionaryMethod() {
foreach (KeyValuePair<string, string> kvp in this)
//...

Categories