开发者

C# object initializer wanting to use wrong Add method

开发者 https://www.devze.com 2022-12-19 08:02 出处:网络
I have the following class hierarchy: public class Row : ICloneable, IComparable, IEquatable<Row>,

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,
    Syste开发者_JS百科m.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:

  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.


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号