Coming back to C# after a few years so I'm a little rusty. Came across this (simplified) code and it's leaving my head scratching.
Why do you have to explicitly implement the IDataItem.Children
property? Doesn't the normal Children
property satisfy the requirement? After all, the property is used directly to satisfy it. Why is it not implicit?
public interface IDataItem {
IEnumerable<string> Children { get; }
}
public class DataItem : IDataItem {
public Collection<string> Children { get; } = new Collection<string>();
// Why doesn't 'Children' above implement this automatically?!
// After all it's used directly to satisfy the requirement!
IEnumerable<string> IDataItem.Children => Children;
}
According to the C# source, here's the definition of Collection<T>
:
[System.Runtime.InteropServices.ComVisible(false)]
public class Collection<T> :
System.Collections.Generic.ICollection<T>,
System.Collections.Generic.IEnumerable<T>, <-- Right Here
System.Collections.Generic.IList<T>,
System.Collections.Generic.IReadOnlyCollection<T>,
System.Collections.Generic.IReadOnlyList<T>,
System.Collections.IList
As you can see, it explicitly implements IEnumerable<T>
and from my understanding, if 'X' implements 'Y' then 'X' is a 'Y', so Collection<String>
is an IEnumerable<String>
so I'm not sure why it isn't satisfied.
Using explicit implementation you can tell the compiler which interface's method you are Overloading and can provide different functionalities for methods of different interfaces. The same is the case for any other type of member like a property, event.
With implicit interface implementations, the members of the interface are public in the class. With explicit implementations, in the class the interface members are not declared as public members and cannot be directly accessed using an instance of the class, but a cast to the interface allows accessing the members.
Yes, you can write an interface without any methods. These are known as marking interfaces or, tagging interfaces. A marker interface i.e. it does not contain any methods or fields by implementing these interfaces a class will exhibit a special behavior with respect to the interface implemented.
Yes, it is mandatory to implement all the methods in a class that implements an interface until and unless that class is declared as an abstract class. Implement every method defined by the interface.
Perhaps this example makes it clearer. We want signatures to match exactly1,2, no substitutions allowed, despite any inheritance relationships between the types.
We're not allowed to write this:
public interface IDataItem {
void DoStuff(string value);
}
public class DataItem : IDataItem {
public void DoStuff(object value) { }
}
Your example is the same, except your asking for return types rather than parameters (and employing a narrowing rather than widening conversion, for obvious reasons). Nontheless, the same principal applies. When it comes to matching signatures, the types must match exactly3.
You can ask for a language that would allow such things to happen and such languages may exist. But the fact of the matter is, these are the rules of C#.
1Outside of some limited support for Co- and Contra-variance involving generics and interfaces/delgates.
2Some may argue about whether signature is the right word to use here since in this case, return types matter as much as parameter types, generic arity, etc; In most other situations where someone talks about C# method signatures, they'll be explicitly ignoring the return type because they're (explicitly or implicitly) considering what the overloading rules say, and for overloading, return types are not part of the signature.
Nonetheless, I'm happy with my usage of the word "signature" here. Signatures aren't formally defined in the C# specification and where it's used, it's often to point out which parts of the signature aren't to be considered for overloading.
3Not to mention the issues that would be raised if your Children
method was returning a struct
that happened to implement IEnumerable<string>
. Now you've got a method that returns the value of a value type and a caller (via the IDataItem
interface who is expecting to receive a reference to an object.
So it's not even that the method could be used as-is. We'd have to (in this case) have hidden boxing conversions to implement the interface. When this part of C# was specced, they were, I believe, trying not to have too much "hidden magic" for code you could easily write yourself.
In your example your "normal" Children property do not actually satisfy the interface requirement. The type is different. It does not really matter that you can cast it - they are different.
Similar example and maybe a bit more obvious is if you would implement an interface with a actual method that returns IEnumerable and tried an ICollection method from the actual class. There is still that compile time error.
As @Ben Voigt said the conversion still generates some code, and if you want to have it - you need to add it implicitly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With