Thursday, January 3, 2008
Explicitly Scoping to an Interface
Many of you are probably aware that C#.NET allows you to explicitly scope methods, properties, events and indexers to an interface. An simple example of scoping a property directly to an interface is shown below.
The question becomes, when should you do this? My answer is only when you have a good reason, and there are some good reasons!
C#.NET does not support multiple inheritence. A class, however, can implement more than one interface. Therefore, it is possible that something in an interface could conflict with something in another interface. It is also possible that something in an interface may conflict with something in the parent class from which your class was derived. Ideally, you would resolve the conflict. But, you can only do that if you are "in control" of the parent class and other interfaces.
Explicitly scoping a property, event, method or indexer to a specific interface allows you have different signatures and implementations where the names conflict.
However, just because one of the properties was specifically scoped does not mean all of them have to be. For example, Since
Given the classes and interfaces above, the following results are obtained.
Sometime you may have to explicitly scope to an interface to resolve conflicts as is mentioned above. However, there are actually reasons you may want to explicitly scope a something to an interface even when you don't have too. For example, if you want compile-time notice that a method implemented in the class was removed from the interface.
Sometimes you have to do it and sometimes you may want to do it, but explicitly scoping something to an interface does have some drawbacks. For starters, the event, property, method or indexer is actually "more private than private", and may yet still be very public. This is because items scoped directly to the interface can only be accessed via the interface; even the class that implements the property, method, event or indexer that is explicitly scoped to an interface cannot access that item without casting itself as the interface. Yet, at the same time, the item could indeed be very accessible from outside the class, derived class or assembly if the interface itself is public.
If you think about it, this is probably the reason why an interface cannot specify access modifiers for individual items within an interface. The interface has no idea whether classes implementing the interface will or will not provide implementations that are explicitly scoped to the interface; that is an implementation detail of the class. Specifying an item in an interface as
Similar arguments can be made for other modifiers such as
Because of the limitations with modifiers, I recommend that items explicitly scoped to the interface should really be nothing more than a stub that calls something else on the class. Doing so allows modifiers such as
Another drawback of explicity scoping an item to an interface is the way it must be handled if reflection is used. For example, the
One interesting thing to point out is that
interface IMyInterface
{
bool MyInterfaceProperty { get; set; }
}
class MyClass : IMyInterface
{
private bool _flag;
IMyInterface.MyInterfaceProperty
{
get { return flag; }
set { _flag = value }
}
}
The question becomes, when should you do this? My answer is only when you have a good reason, and there are some good reasons!
C#.NET does not support multiple inheritence. A class, however, can implement more than one interface. Therefore, it is possible that something in an interface could conflict with something in another interface. It is also possible that something in an interface may conflict with something in the parent class from which your class was derived. Ideally, you would resolve the conflict. But, you can only do that if you are "in control" of the parent class and other interfaces.
Explicitly scoping a property, event, method or indexer to a specific interface allows you have different signatures and implementations where the names conflict.
interface IA
{
int Foo {get;}
}
interface IB
{
bool Foo {get;}
}
class ClassA
{
int Foo
{
get { return 1; }
}
}
class ClassB : ClassA, IA, IB
{
new int Foo
{
get { return 2; }
}
int IA.Foo
{
get { return 3; }
}
bool IB.Foo
{
get { return false; }
}
}
However, just because one of the properties was specifically scoped does not mean all of them have to be. For example, Since
ClassA.Foo and IA.Foo share the same signature, they can also share the same implementation as is shown below.
class ClassB2 : ClassA, IA, IB
{
// This method hides Foo from the parent class, and also
// is used as the implementation of IA.Foo.
new int Foo
{
get { return 2; }
}
bool IB.Foo
{
get { return false; }
}
}
Given the classes and interfaces above, the following results are obtained.
ClassB b = new ClassB();
b.Foo.ToString(); // "2"
(b as ClassA).Foo.ToString(); // "1"
(b as IA).Foo.ToString(); // "3"
(b as IB).Foo.Tostring(); // "False"
ClassB2 b2 = new ClassB2
b2.Foo.ToString(); // "2"
(b2 as ClassA).Foo.ToString(); // "1"
(b2 as IA).Foo.ToString(); // "2"
(b2 as IB).Foo.ToString(); // "False"
Sometime you may have to explicitly scope to an interface to resolve conflicts as is mentioned above. However, there are actually reasons you may want to explicitly scope a something to an interface even when you don't have too. For example, if you want compile-time notice that a method implemented in the class was removed from the interface.
Sometimes you have to do it and sometimes you may want to do it, but explicitly scoping something to an interface does have some drawbacks. For starters, the event, property, method or indexer is actually "more private than private", and may yet still be very public. This is because items scoped directly to the interface can only be accessed via the interface; even the class that implements the property, method, event or indexer that is explicitly scoped to an interface cannot access that item without casting itself as the interface. Yet, at the same time, the item could indeed be very accessible from outside the class, derived class or assembly if the interface itself is public.
public interface ISomeInterface
{
string SomeMethod { get; }
string SomeOtherMethod { get; }
}
class SomeClass : ISomeInterface
{
string SomeMethod()
{
return "Hello World 1";
}
ISomeInterface.SomeOtherMethod()
{
return "Hello World 2";
}
void Test()
{
string someMetod = SomeMethod();
#if (true)
// This DOES compile because this instance is cast to the interface
string someOtherMethod = (this as ISomeInterface).SomeOtherMethod();
#else
// This DOES NOT compile because even a class cannot directly access
// something explicitly scoped to an interface.
string someOtherMethod = SomeOtherMethod();
string someOtherMethod = ISomeInterface.SomeOtherMethod();
#endif
}
}
class SomeOtherClass()
{
void TestMethod()
{
ISomeInterface i = new SomeClass();
string result = i.SomeOtherMethod();
}
}
If you think about it, this is probably the reason why an interface cannot specify access modifiers for individual items within an interface. The interface has no idea whether classes implementing the interface will or will not provide implementations that are explicitly scoped to the interface; that is an implementation detail of the class. Specifying an item in an interface as
private, protected, internal or public is absolutely nonsensical because if a class chooses to scope an item to the interface then that item is inherently "more private than private".Similar arguments can be made for other modifiers such as
virtual and static. If an item is explicitly scoped to an interface, then it cannot even be accessed directly by the class in which it is implemented; how could you expect it to be overriden by a derived class? Likewise, static makes no sense for an item within an interface; if there is no instance of an object, there is nothing to cast to the interface.Because of the limitations with modifiers, I recommend that items explicitly scoped to the interface should really be nothing more than a stub that calls something else on the class. Doing so allows modifiers such as
virtual to be used as need, as is shown in the following example.
interface IThisInterface
{
int ThisInterfaceProperty { get; }
}
class ThisClass : IThisInterface
{
int IThisInterface.ThisInterfaceProperty
{
get { return IThisInterface_ThisInterfaceProperty; }
}
protected virtual int IThisInterface_ThisInterfaceProperty
{
get { return 100; }
}
}
class ThisOtherClass : ThisClass
{
protected override int IThisInterface_ThisInterfaceProperty
{
get { return 200; }
}
}
ThisClass thisClass = new ThisClass();
int thisResult = (thisClass as IThisInterface).ThisProperty; // 100
ThisOtherClass thisOtherClass = new ThisOtherClass();
int thisOtherResult = (thisOtherClass as IThisInterface).ThisProperty; // 200
Another drawback of explicity scoping an item to an interface is the way it must be handled if reflection is used. For example, the
Type.GetProperty() method will not return a property that is explicitly scoped to an interface. Rather, the Type.GetInterfaceMap() method may be used.One interesting thing to point out is that
Type.GetInterfaceMap returns an InterfaceMappping object, and that object has an InterfaceMethods property but does not also have corresponding InterfaceProperties, InterfaceEvent or InterfaceIndexers properties. This is because, under the covers, these other types ultimately call methods that are contained in the array returned by InterfaceMethods property. For example, the getter for ThisInterfaceProperty corresponds to a method named get_ThisInterfaceProperty().Subscribe to Posts [Atom]