Translate

Monday 9 April 2018

Explicit interface method - C#

Note: Putting the angular brackets < and > in a blogger post is more difficult than generics !

Continuing with generics, one of  my favorite language features, but this time in C#, the more dynamic of generic implementation in all programming languages, the premise, again from an example from Stackoverflow, is that there are two interfaces, IEquipment and 
IEquipmentDataProvider, with the latter providing for a generic method, GetEquipment, that returns a type of IEquipment.   

The question being on Stackoverflow ie., whether 
IEquipment
GetEquipment<E>(string Path) where E : IEquipment, new();

is correct or should there be an alternate way of working on the intent? 

An intent is what an interface is about and so when a constraint is declared on a generic method, or a normal method, the expansion of the constraint at implementation is what reveals the design of the intent. In this instance, it is a constraint that says all implementing classes must be of type 
IEquipment (
where E : IEquipment) and should have a parameterless constructor - , new().

So, what does it mean as a design when the interface IEquipmentDataProvider declares it like so,

public interface IEquipmentDataProvider
{
  IEquipment GetEquipment<E>(string Path) where E : IEquipment, new(); 
} 


public interface IEquipment{

}
public interface IEquipmentDataProvider:IEquipment
{
  IEquipment GetEquipment<E>(string Path) where E : IEquipment, new();
}
public class Equipment:IEquipment{
public Equipment(){

}
public IEquipment GetEquipment<E>(string Path){
Equipment eqp=new Equipment();
IEquipment ieq=(IEquipment) eqp;
return ieq;
}

public class EquipmentDataProvider:IEquipmentDataProvider{
public EquipmentDataProvider(){

}
public IEquipment GetEquipment<E>(string Path){
EquipmentDataProvider eqp=new EquipmentDataProvider();
IEquipmentDataProvider iedp = (IEquipmentDataProvider) eqp;
return iedp;
}
public static void Main(){
IEquipmentDataProvider da=(IEquipmentDataProvider)new EquipmentDataProvider();
IEquipment eq = (IEquipment)da.GetEquipment<Equipment>("somepath");
System.Console.WriteLine(eq);
}
}

For the above code, the compiler rejects the interface implementation because E cannot be expanded into a type conforming to the constraints because a type of IEquipment does not exist with a parameterless constructor and a corresponding GetEquipment method. ie., had the IEquipment interface declared the GetEquipment method in it instead of the IEquipmentDataProvider, the error would have been for IEquipment because the implementing class, Equipment, too, has not implemented the method as an interface method!!


It can be quite vexing if one does not know C# well, which has a feature where a method can be explicitly defined so that the interface implementation conforms to what the compiler expects.

This means that you simply qualify the method with the interface name prefixed, like so:

public IEquipment IEquipmentDataProvider.GetEquipment(string Path){

}

But since it is an explicit method definition, the compiler throws an error that the public modifier cannot be applied on it!


Because it is typed specifically as an interface method! Cool, isn't it!?

Modify the signature of the method and the complete code is as below:

public interface IEquipment{

}

public interface IEquipmentDataProvider:IEquipment
{
  IEquipment GetEquipment<E>(string Path) where E : IEquipment, new();
}
public class Equipment:IEquipment{
public Equipment(){}
public IEquipment GetEquipment<E>(string Path){
Equipment eqp=new Equipment();
IEquipment ieq=(IEquipment) eqp;
return ieq;

}
public class EquipmentDataProvider:IEquipmentDataProvider{
public EquipmentDataProvider(){}
IEquipment IEquipmentDataProvider.GetEquipment<E>(string Path){
EquipmentDataProvider eqp=new EquipmentDataProvider();
IEquipmentDataProvider iedp = (IEquipmentDataProvider) eqp;
return iedp;
}
public static void Main(){
IEquipmentDataProvider da=(IEquipmentDataProvider)new EquipmentDataProvider();
IEquipment eq = (IEquipment)da.GetEquipment<Equipment>("somepath");
System.Console.WriteLine(eq);
}
}

and, the output, even though the method returns an IEquipment type is actually an EquipmentDataProvider type!!



Happy C#-ing and generic interfacing, whatever may be the constraints!

No comments: