Sarah Vessels
Sarah Vessels

Reputation: 31640

C# object initializer wanting to use wrong Add method

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.

Upvotes: 6

Views: 1746

Answers (3)

Seth Petry-Johnson
Seth Petry-Johnson

Reputation: 12085

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, ""})
};

Upvotes: 1

Daniel Schaffer
Daniel Schaffer

Reputation: 57852

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:

  1. Implement IDictionary<MyEnum, string> in addition to IDictionary<MyEnum, string>, including the dependent interfaces (ICollection<KeyValuePair<MyEnum, string>>, etc).
  2. Implement IDictionary<MyEnum, string> instead of IDictionary<MyEnum, string>, again including the dependent interfaces.
  3. 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.

Upvotes: 5

Ruben
Ruben

Reputation: 15525

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.

Upvotes: 8

Related Questions