Reputation: 61
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
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
, orstatic
.
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
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