views:

283

answers:

4

I'm not sure what's going on. I have the following base class:

public class MyRow : IStringIndexable, System.Collections.IEnumerable,
    ICollection<KeyValuePair<string, string>>,
    IEnumerable<KeyValuePair<string, string>>,
    IDictionary<string, string>
{
    ICollection<string> IDictionary<string, string>.Keys { }
}

And then I have this derived class:

public class MySubRow : MyRow, IXmlSerializable, ICloneable,
    IComparable, IEquatable<MySubRow>
{
    public bool Equals(MySubRow other)
    {
        // "MyRow does not contain a definition for 'Keys'"
        foreach (string key in base.Keys) { }
    }
}

Why do I get that error? "'MyNamespace.MyRow' does not contain a definition for 'Keys'". Both classes are in the MyNamespace namespace. I tried accessing this.Keys and base.Keys and neither works from within MySubRow. I tried marking the Keys property as public in MyRow but got "The modifier 'public' is not valid for this item", I think because it's necessary to implement an interface.

+6  A: 

You're implementing the Keys property explicitly. If you want to make that member publicly accessible (or protected), change IDictionary<string, string>.Keys to Keys and add the appropriate visibility modifier in front of it.

public ICollection<string> Keys { ... }

or

protected ICollection<string> Keys { ... }

You could reference base as an instance of IDictionary<string, string> as well:

((IDictionary<string, string>)base).Keys

More Information

(Judging by your comments you appear to be familiar with the distinction, but others may not be)

C# interface implementation can be done two ways: implicitly or explicitly. Let's consider this interface:

public interface IMyInterface
{
    void Foo();
}

An interface is just a contract for what members a class must make available to code that is calling it. In this case, we have one function called Foo that takes no parameters and returns nothing. An implicit interface implementation means that you must expose a public member that matches the name and signature of the member on the interface, like this:

public class MyClass : IMyInterface
{
    public void Foo() { }
}

This satisfies the interface because it exposes a public member on the class that matches every member on the interface. This is what is usually done. However, it is possible to explicitly implement the interface and map the interface function to a private member:

public class MyClass : IMyInterface
{
    void IMyInterface.Foo() { }
}

This creates a private function on MyClass that is only accessible to outside callers when they are referring to an instance of IMyInterface. For instance:

void Bar()
{
    MyClass class1 = new MyClass();
    IMyInterface class2 = new MyClass();

    class1.Foo(); // works only in the first implementation style
    class2.Foo(); // works for both
}

Explicit implementations are always private. If you want to expose it outside of the class you'll have to create another member and expose that, then use the explicit implementation to call the other member. This is usually done so that a class can implement interfaces without cluttering up its public API, or if two interfaces expose members with the same name.

Adam Robinson
The OP is accessing the member, not trying to implement it
JaredPar
@Jared: Look at his first class. The property is implemented there, and it's done so explicitly.
Adam Robinson
@Adam, gotcha, missed the explicit implementation
JaredPar
@Adam: _her_ first class. :) Thanks, changing it to simply `public ICollection<string> Keys` worked.
Sarah Vessels
@Sarah: mea culpa! I didn't bother reading the name of the OP.
Adam Robinson
@Rob: Yes, you can cast `base` or `this` to the interface type, but I got the impression that explicit implementation wasn't intentional here.
Adam Robinson
@Adam happy with your rewrite :)
Rob Fonseca-Ensor
Downvoter care to explain why?
Adam Robinson
+3  A: 

Since you're implementing the IDictionary<TKey,TValue> interface explicitly, you first have to cast this to IDictionary<string,string>:

public bool Equals(MySubRow other)
{
    foreach (string key in ((IDictionary<string,string>)this).Keys) { }
}
dtb
Thanks. I ended up removing the explicit interface declaration in `MyRow`. Now it's just `public ICollection<string> Keys` and calling `base.Keys` works.
Sarah Vessels
@Sarah, in some situations you'll have to use what @dtb suggested, because multiple interfaces will define the same method name...
Rob Fonseca-Ensor
@Rob: that's actually what I had done in the past and then, as a result of refactoring, reduced the interfaces the class implements so the explicit implementation was no longer necessary.
Sarah Vessels
A: 

I believe both Jared and Adam are correct: the property is explitcity implemented on the base class, resulting in it not being public. You should be able to change it to an implicit implementation and make it happy:

public class MyRow : IStringIndexable, System.Collections.IEnumerable,
    ICollection<KeyValuePair<string, string>>,
    IEnumerable<KeyValuePair<string, string>>,
    IDictionary<string, string>
{
    ICollection<string> Keys { }
}
STW
I made it implicit and `public`, yep.
Sarah Vessels
A: 

protected will allow inheriting classes to see it, but no other class

Jay
That wasn't the problem, though. I couldn't mark it as `public` or `protected` because I was explicitly implementing the interface. While explicitly implementing it, adding a modifier like `public` caused a separate compilation error. I ended up making it an implicit implementation, _then_ adding `public`: `public ICollection<string> Keys`.
Sarah Vessels