While attempting to override the explicit interface implementation of the ICollection<T>.IsReadOnly property from the Collection<T> class, I came across some documents stating that explicit interface member implementations cannot be overridden because they cannot have modifiers such as virtual or abstract. On MSDN they even go as far as specifying how to make an explicit interface member implementation available for inheritance by creating another abstract or virtual member which is called by the explicit interface member implementation. No problems so far.
But then I wonder: Why is it possible in C# to override any explicitly implemented interface member just by specifying the interface explicitly?
For example, suppose I have a simple interface like this, with a property and method:
public interface IMyInterface
{
bool AlwaysFalse { get; }
bool IsTrue(bool value);
}
And a class A which implements the interface explicitly, and has a method Test() which calls its own interface member implementation.
public class A : IMyInterface
{
bool IMyInterface.AlwaysFalse
{ get { return false; } }
bool IMyInterface.IsTrue(bool value)
{ return value; }
public bool Test()
{ return ((IMyInterface)this).AlwaysFalse; }
}
As you can see, none of the four members are virtual or abstract, so when I define a class B like this:
public class B : A
{
public bool AlwaysFalse
{ get { return true; } }
public bool IsTrue(bool value)
{ return !value; }
}
Then you'd expect an instance of B cast to A to behave like A. And it does:
A a = new A();
Console.WriteLine(((IMyInterface)a).AlwaysFalse); // False
Console.WriteLine(((IMyInterface)a).IsTrue(false)); // False
Console.WriteLine(a.Test()); // False
A b = new B();
Console.WriteLine(((IMyInterface)b).AlwaysFalse); // False
Console.WriteLine(((IMyInterface)b).IsTrue(false)); // False
Console.WriteLine(b.Test()); // False
Now comes the catch. Create a class C which is an exact copy of B except for one thing in the class declaration:
public class C : A, IMyInterface
{ /* ... same as B ... */ }
Now an instance of C, when cast to A, doesn't behave like A but like C:
A c = new C();
Console.WriteLine(((IMyInterface)c).AlwaysFalse); // True
Console.WriteLine(((IMyInterface)c).IsTrue(false)); // True
Console.WriteLine(c.Test()); // True
Even the Test() method now calls the overridden method in C! Why is this?
This has nothing to do with explicit interface implementation; it's simply a consequence of the general rules of inheritance and interface mapping: you would see exactly the same results if type A provided an implicit, rather than explicit, implementation of IMyInterface.
Type B inherits from type A. Nothing is overridden.
B provides its own AlwaysFalse and IsTrue members but they don't implement IMyInterface; The implementation of IMyInterface is provided by the members inherited from A: when an instance of type B is cast to IMyInterface then it behaves in exactly the same way as an instance of type A because A is providing the members that implement the interface.
Type C inherits from type A. Again, nothing is overridden.
C provides its own AlwaysFalse and IsTrue members but this time those members do implement IMyInterface: when an instance of type C is cast to IMyInterface then the members of C provide the interface implementation rather than those of A.
Because type A implements IMyInterface explicitly the compiler doesn't warn that the members of B and C are hiding the members of A; In effect those members of A were already hidden due to the explicit interface implementation.
If you changed type A to implement IMyInterface implicitly rather than explicitly then the compiler would warn that the members of B and C are hiding, not overriding, the members of A and that you should ideally use the new modifier when declaring those members in B and C.
Here are some relevant bits from the language specification. (Sections 20.4.2 and 20.4.4 in the ECMA-334 spec; sections 13.4.4 and 13.4.6 in the Microsoft C#4 spec.)
20.4.2 Interface mapping
The implementation of a particular
interface member I.M, where I is
the interface in which the member M
is declared, is determined by
examining each class or struct S,
starting with C and repeating for
each successive base class of C,
until a match is located.
20.4.4 Interface re-implementation
A class that inherits an interface
implementation is permitted to
re-implement the interface by
including it in the base class list. A
re-implementation of an interface
follows exactly the same interface
mapping rules as an initial
implementation of an interface. Thus,
the inherited interface mapping has no
effect whatsoever on the interface
mapping established for the
re-implementation of the interface.
Related
Imagine a situation where two marker interfaces A and B guard single Base interface:
interface Base
{
void Hello();
}
interface A: Base
{
}
interface B: Base
{
}
Is there a way to define class C that implements both A and B while providing marker interface specific Hello implementations? Note that Base, A and B interfaces are declared in an external library so I could not modify it.
If I do this
class C: A, B
{
void A.Hello() =>
Console.Out.WriteLine("A");
void B.Hello() =>
Console.Out.WriteLine("B");
}
...it results in CS0539 compiler error:
member in explicit interface declaration is not a member of interface.
No, it's not possible in C# without modifying the interfaces. The only explicit interface implementation that is possible is Base.Hello:
class C: A, B
{
void Base.Hello() =>
Console.Out.WriteLine("Base");
}
interface IBase
{
string Name { get; }
}
class Base : IBase
{
public Base() => this.Name = "Base";
public string Name { get; }
}
class Derived : Base//, IBase
{
public Derived() => this.Name = "Derived";
public new string Name { get; }
}
class Program
{
static void Main(string[] args)
{
IBase o = new Derived();
Console.WriteLine(o.Name);
}
}
In this case output will be "Base".
If I explicitly state that Derived implements IBase (which is in fact already implemented by base class Base and such annotation seem to be useless) the output will be "Derived"
class Derived : Base, IBase
{
public Derived() => this.Name = "Derived";
public new string Name { get; }
}
What's the reason for such behavior?
VS 15.3.5, C# 7
It's explained in sections 13.4.4 to 13.4.6 of the C# 5 specification. The relevant sections are quoted below, but basically if you explicitly state that a class implements an interface, that triggers interface mapping again, so the compiler takes that class as the one to use to work out which implementation each interface member is mapped to.
13.4.4 Interface mapping
A class or struct must provide implementations of all members of the interfaces that are listed in the base class list of the class or struct. The process of locating implementations of interface members in an implementing class or struct is known as interface mapping.
Interface mapping for a class or struct C locates an implementation for each member of each interface specified in the base class list of C. The implementation of a particular interface member I.M, where I is the interface in which the member M is declared, is determined by examining each class or struct S, starting with C and repeating for each successive base class of C, until a match is located:
If S contains a declaration of an explicit interface member implementation that matches I and M, then this member is the implementation of I.M.
Otherwise, if S contains a declaration of a non-static public member that matches M, then this member is the implementation of I.M. If more than one member matches, it is unspecified which member is the implementation of I.M. This situation can only occur if S is a constructed type where the two members as declared in the generic type have different signatures, but the type arguments make their signatures identical.
...
13.4.5 Interface implementation inheritance
A class inherits all interface implementations provided by its base classes.
Without explicitly re-implementing an interface, a derived class cannot in any way alter the interface mappings it inherits from its base classes. For example, in the declarations
interface IControl
{
void Paint();
}
class Control: IControl
{
public void Paint() {...}
}
class TextBox: Control
{
new public void Paint() {...}
}
the Paint method in TextBox hides the Paint method in Control, but it does not alter the mapping of Control.Paint onto IControl.Paint, and calls to Paint through class instances and interface instances will have the following effects
Control c = new Control();
TextBox t = new TextBox();
IControl ic = c;
IControl it = t;
c.Paint(); // invokes Control.Paint();
t.Paint(); // invokes TextBox.Paint();
ic.Paint(); // invokes Control.Paint();
it.Paint(); // invokes Control.Paint();
...
13.4.6 Interface reimplementation
A class that inherits an interface implementation is permitted to re-implement the interface by including it in the base class list.
A re-implementation of an interface follows exactly the same interface mapping rules as an initial implementation of an interface. Thus, the inherited interface mapping has no effect whatsoever on the interface mapping established for the re-implementation of the interface. For example, in the declarations
interface IControl
{
void Paint();
}
class Control: IControl
{
void IControl.Paint() {...}
}
class MyControl: Control, IControl
{
public void Paint() {}
}
the fact that Control maps IControl.Paint onto Control.IControl.Paint doesn’t affect the re-implementation in MyControl, which maps IControl.Paint onto MyControl.Paint.
If Derived does not implement IBase and declares new string Name, that means that Derived.Name and IBase.Name are logically not the same. So when you access IBase.Name, it looks for it in Base class, implementing IBase. If you remove new string Name property, the output will be Derived, because now Derived.Name = Base.Name = IBase.Name. If you implement IBase excplicitly, the output will be Derived, because now Derived.Name = IBase.Name. If you cast o to Derived, the output will be Derived, because now you are accessing Derived.Name instead of IBase.Name.
In C++, you can invoke method's from a template argument like so:
template<class T> class foo
{
T t;
t.foo();
}
But in C#, it looks like this is not possible:
class foo<T>
{
T t;
public void foo() {
t.foo(); // Generates a compiler error
}
};
I suppose this probably isn't possible in C#, is it?
You have discovered the difference between templates and generics. Though they look similar they are in fact quite different.
A template need be correct only for the type arguments that are actually provided; if you provide a T that does not have a method foo then the compilation fails; if you provide only type arguments that have a foo then compilation succeeds.
By contrast a generic must be correct for any possible T. Since we have no evidence that every possible T will have a method foo then the generic is illegal.
Yes, if you know that the generic type placeholder T implements a member from a base class or interface, you can constrain the type T to that base class or interface using a where clause.
public interface IFooable
{
void Foo();
}
// ...
public class Foo<T> where T : IFooable
{
private T _t;
// ...
public void DoFoo()
{
_t.Foo(); // works because we constrain T to IFooable.
}
}
This enables the generic type placeholder T to be treated as an IFooable. If you do not constrain a generic type placeholder in a generic, then it is constrained to object which means only object's members are visible to the generic (that is, you only see members visible to an object reference, but calling any overridden members will call the appropriate override).
Note: This is additionally important because of things like operator overloading (remember that operators are overloaded, not overridden) so if you had code like this:
public bool SomeSuperEqualsChecker<T>(T one, T two)
{
return one == two;
}
This will always use object's == even if T is string. However, if we had:
public bool SomeSuperEqualsChecker<T>(T one, T two)
{
// assume proper null checking exists...
return one.Equals(two);
}
This WOULD work as expected with string because Equals() is overridden, not overloaded.
So, the long and the short is just remember that an unconstrained generic placeholder does represent any type, but the only calls and operations visible are those visible on object.
In addition to interface/base class constraints, there are a few other constraints:
new() - Means that the generic type placeholder must have a default constructor
class - Means that the generic type placeholder must be a reference type
struct - Means that the generic type placeholder must be a value type (enum, primitive, struct, etc)
For example:
public class Foo<T> where T : new()
{
private T _t = new T(); // can only construct T if have new() constraint
}
public class ValueFoo<T> where T : struct
{
private T? _t; // to use nullable, T must be value type, constrains with struct
}
public class RefFoo<T> where T : class
{
private T _t = null; // can only assign type T to null if ref (or nullable val)
}
Hope this helps.
You need to add a type constraint to your method.
public interface IFoo {
void Foo();
}
public class Foo<T> where T : IFoo {
T t;
public void foo() {
t.Foo(); // Generates a compiler error
}
}
It is possible if you are willing to accept generic type constraints. This means that your generic type must be constrained to derive from some base class or implement some interface(s).
Example:
abstract class SomeBase
{
public abstract DoSomething();
}
// new() ensures that there is a default constructor to instantiate the class
class Foo<T> where T : SomeBase, new()
{
T t;
public Foo()
{
this.t = new T();
this.t.DoSomething(); // allowed because T must derive from SomeBase
}
}
I have a class which inherits an interface. An interface member method is implemented in my class without an access modifier (so, by default it's private ) .
I am getting the error "cannot implement an interface member because it is not public".
Why it is not allowed? Can't I override the accessibility?
Here's an example of why it doesn't make sense to be able to override the visibility:
interface someI
{
void doYourWork();
}
public class A : someI
{
public void doYourWork()
{
//...
}
}
public class B : someI
{
private void doYourWork()
{
//...
}
}
void Main()
{
List<someI> workers = getWorkers();
foreach(var worker in workers)
worker.doYourWork();
}
What happens when your worker is of type B? You're calling a method as if it were public, but it's a private method. If you want this functionality, then it's not really a private method is it?
If you only want it to be public when referenced through your interface, then you can define it as such:
public class B : someI
{
void someI.doYourWork()
{
//...
}
}
And you end up with this:
var b = new B();
b.doYourWork(); // Not accessible
((someI)b).doYourWork(); // Accessible
Methods have to be implemented public because they have to be callable through the interface, thus from where the interface is accessible as a type.
You have a few options here to "change" the visibility of that method. Given:
public interface IFoo
{
bool IsFoo();
}
A. Implement the method explicitly
public class Foo : IFoo
{
bool IFoo.IsFoo() { return true; }
}
The method will only be available through the interface (IFoo in this case.)
B. Change the visibility of the interface
Define the interface as internal instead of public. As a consequence, however, Foo will have to be internal too.
Requiring that an interface implementation be public is simply a logical requirement. When you implement an interface, you're telling the compiler "Hey I implement every method on this interface". So making the method private makes it no longer accessible - and logically not implemented. Interfaces serve as a contract to code that uses your object saying you can always call any method defined in the interface on my object. If the implementing method were private, that would not longer be true.
If you want to hide your implementation from, say Intellisense, then you can simply implement the method explicitly as #Bryan mentions.
I have one specific query with the interfaces.
By default interface methods are abstract and virtual so if we implement that interface and gives definition in the class we actually override that method but when we mark the method as a virtual again in the implementing class why the compiler is not considering that we are actually trying to hide the original interface virtual method.
Like if we have a virtual method in the base class and derived class again marked the method as virtual in that case compiler gives the warning that you are hiding the base class method so use new if you are intentionally hiding the base class method.
public interface ITestInterface
{
void virtualmethod(); // this method is by default virtual.
}
public class TestInterface :ITestInterface
{
public virtual void virtualmethod()
{
// Now compiler should consider that i am actually hiding the interface virtual method.
}
}
if you build the above code for interface and open in ILDASM you will see the code like this:
.method public hidebysig newslot abstract virtual
instance void virtualmethod() cil managed
{
}//end of method ITestInterface::virtualmethod
Methods that are implemented from an interface are not virtual by default. You are merely providing an implementation of the contract defined in the interface definition. By marking the method as virtual, you are allowing derived classes to provide additional or separate implementation while still honoring the contract as defined.
Consider this example:
interface IAnimal
{
string Speak();
}
class Dog : IAnimal
{
public string Speak()
{
return "Bark!";
}
}
The Dog class is implementing the interface by providing an implementation of the contract IAnimal. There are no virtual methods here and no overriding.
Now consider this example:
interface IAnimal
{
string Speak();
}
class Dog : IAnimal
{
public virtual string Speak()
{
return "Bark!";
}
}
class GoldenRetriever : Dog
{
public override string Speak()
{
return "I am a golden retriever who says "
+ base.Speak();
}
}
Now the Dog class has declared Speak to be virtual which allows derived classes to provide an additional or new implementation. This does not break the contract with IAnimal as any call to the Speak method still returns a string.
Ok, one last example. Remember that interfaces don't require an implementation - they only require that the contract is satisfied. This means that the interface only cares that a member exists in the implementing class that has a matching signature. This means that we could also do this:
interface IAnimal
{
string Speak();
}
abstract class Dog : IAnimal
{
public abstract string Speak();
}
class GoldenRetriever : Dog
{
public override string Speak()
{
return "I am a golden retriever";
}
}
Notice now that the Dog class provides no implementation at all for Speak yet has satisfied the requirements of the contract.
Interfaces are also inherited from class to class so in all the examples above both Dog and GoldenRetriever implement the IAnimal interface. Neither class hide the Speak method - both classes implement it.
Ok, I think your confusion may be coming from the fact that the virtual method is defined in an interface, not a class. Here is the IL for the interface I defined above:
.class private interface abstract auto ansi IAnimal
{
.method public hidebysig newslot abstract
virtual instance string Speak() cil managed
{
}
}
While you are correct that the method is defined as virtual you also need to notice that the type here is designated as an interface. This is purely an implementation detail of the MSIL generated by Microsoft's C# compiler - another compiler could easily generate different code as long as semantically it provided the same result.
The important thing here is this: even though the method is declared as virtual in the interface that does not mean that it is the same thing as a virtual method declared in class.
Interface is not Base Class, so implementation methods are not overriden. Interface only declares the methods, Interface methods are not virtual by default, infact interfaces only declare the methods that are available on the class that implements that interface.
Declaration can not be virtual.
Implementation can or cannot be virtual that is completely dependent on the implementer's logic.
There is a mix-up of the term 'virtual' here, between IL and C#.
They do not completely correspond. Virtual in the IL sense means "it's called indirect" via a VMT(virtual method table), that is about the same mechanism for class overriding and interface implementation.
In the IL sense, an interface member must be marked virtual - there is no way around.
But if you look in the implementation, it's marked as 'virtual final'. That is something you cannot achieve in C#. 'Final' means, it cannot be overriden. It does not become virtual in the meaning of C#, unless you declare it manually as 'virtual' or 'abstract' in C#.
The implicit interface implementation of C# (it doesn't exist in VB.NET or IL) is quiet powerful. It does attach the Method of the implementing class, that matches in Name-Parameters-ReturnValue (the Signature, or SigAndName in the IL wording).
This includes using base class implementations for the methods.
public interface ITest
{
double MethodC(double a, double b, double c, double d);
}
internal class BaseClass
{
public double MethodC(double a, double b, double c, double d)
{
return a+b+c+d;
}
}
internal class OtherClass : BaseClass , ITest
{
}
This actually works fine.
But C# is doing a Trick here, Cause you use the BaseClass.MethodC as an interface implementation, it's marked as final virtual in the BaseClass.
Yes, the way how BaseClass is implemented, depends on how BaseClass is used.
BaseClass.MethodC is modified, cause it's used to implement ITest.MethodC in a derived class. This even works over file and project boundaries, as long as the source code of BaseClass is in the same solution.
So the output of the compilation of a project, is not the same, if you compile it by itself, or in a big solution together with other products. This is quiet noticable.
If the source code of BaseClass is not available, if you just linked into a DLL, then C# will generate a Wrapper to use the BaseClass implementation.
It will actually do this:
internal class OtherClass : BaseClass , ITest
{
double ITest.MethodC(double a, double b, double c, double d)
{
return base.MethodC(a, b, c, d)
}
}
This is done in secret, but it's absolutely necessary to have a method marked as virtual in the IL sense.