copygirl
copygirl

Reputation: 61

C# Explicitly override virtual interface method of base type

I have an abstract class DataBase which is used as base class for different types of data, such as simple value types (byte, int, string etc.) and more complex data structures like DataList and DataDictionary. DataList implements IList<DataBase> and DataDictionary implements IDictionary<string, DataBase>.

For simplicity's sake, I went ahead and put a couple of things I'll often use in the DataBase class, so casting won't be necessary:

public virtual DataBase this[string name] {
    get { throw new NotSuppportedException(); }
    set { throw new NotSuppportedException(); }
}
public virtual DataBase this[int index] { ...

// Example usage:
var someData = rootData["SomeList"][10];

These methods are then overridden in base classes. Or not, in which case it throws the exception when used. To make things a little simpler I also wanted to implement IEnumerable<DataBase> in a similar way:

public virtual IEnumerator<DataBase> GetEnumerator() {
    throw new NotSuppportedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
    return GetEnumerator();
}

But since DataDictionary is an IDictionary, and therefore IEnumerable<KeyValuePair<string, DataBase>>, I've run into the issue of not being able to override DataBase's GetEnumerator(). I've tried a number of different ways:

(public|protected) (override) IEnumerator<DataBase> DataBase.GetEnumerator()
(public|protected) (override) IEnumerator<DataBase> IEnumerable<DataBase>.GetEnumerator()

The modifier 'override' is not valid for this item (CS0106)

Now, I wasn't sure what to look for regarding this issue - what is this called even? - or which limitation (if any) is preventing me from doing what I'm trying to do and why it may be there.


Related question and answer "C# overriding an interface contract method of a base class" does not solve the issue. If you were to change x's type to TestBase, the code outputs "Base".

Upvotes: 1

Views: 626

Answers (2)

Joe Farrell
Joe Farrell

Reputation: 3542

The C# spec explicitly disallows the use of override on an explicitly implemented interface member in section 13.4.1:

It is a compile-time error for an explicit interface member implementation to include access modifiers, and it is a compile-time error to include the modifiers abstract, virtual, override, or static.

So if you want to override DataBase::GetEnumerator() in DataDictionary, you need a non-explicit implementation. But in order to write an override using a non-explicit implementation, you must have explicitly implemented IEnumerable<KeyValuePair<string, DataBase>>::GetEnumerator(), because if you use a non-explicit implementation for that method, it will hide DataBase::GetEnumerator(), since the two methods differ only by their return types.

Bottom line: I can't see why you'd want to design something like this. (You seem to have arrived at the same conclusion in your answer when you described it as "doing-something-way-too-silly-and-complicated!")

Upvotes: 1

copygirl
copygirl

Reputation: 61

Now, I've previously run into these sort of issues, which is often a case of doing-something-way-too-silly-and-complicated. One obvious solution I can think of is moving the implementation into the DataBase class directly:

public IEnumerator<DataBase> GetEnumerator() {
    if (this is DataList)
        return ((DataList)this).GetEnumerator();
    else if (this is DataDictionary)
        return ((DataDictionary)this).Values.GetEnumerator();
    else throw new NotSupportedException();
}

But obviously, it's definitely not the cleanest solution.

Upvotes: 0

Related Questions