This is one of the most complicated elements of the c# language though it is incredibly important for building well defined components. As such, c# falls short. However it is definitely possible to make this work.
The trick is to have 3 parts:
- A non generic interface that contains all requirements of the interface.
- A generic abstract class that implements the non generic interface and performs the type conversions as necessary.
- A class that implements the generic abstract class with the appropriately typed results
For example:
public interface INonGenericInterface{
void Execute(object input);
object GetModel();
}
public abstract class IGenericInterfaceBase<T> : INonGenericInterface{
void INonGenericInterface.Execute(object input){
Execute((T) input);
}
object INonGenericInterface.GetModel(){
return GetModel();
}
protected abstract void Execute(T input);
protected abstract T GetModel();
}
public class ImplementingClass : IGenericInterfaceBase<ModelClass>{
protected override void Execute(ModelClass input){ /*Do something with the input */ }
protected override ModelClass GetModel(){ return new ModelClass();}
}
//Extras for demo
public class ModelClass { }
public class ModelClass2 { }
public class ImplementingClass2 : IGenericInterfaceBase<ModelClass2>
{
protected override void Execute(ModelClass2 input) { /*Do something with the input */ }
protected override ModelClass2 GetModel() { return new ModelClass2(); }
}
var agi = new INonGenericInterface[] { new ImplementingClass(), new ImplementingClass2() };
agi[0].Execute(); var model = agi[0].GetModel();
agi[1].Execute(); var model2 = agi[1].GetModel();
//Check the types of the model and model2 objects to see that they are appropriately typed.
This structure is incredibly useful when coordinating classes w/ one another because you're able to indicate that an implementing class will make use of multiple classes and have type checking validate that each class follows established type expectations. In addition, you might consider using an actual class instead of object for the non-generic class so that you can execute functions on the result of the various non-generic calls. Using this same design you can have those classes be generic classes w/ their own implementations and thus create incredibly complex applications.
To OP: Please consider changing the accepted answer to this to raise awareness of the correct approach as all previously stated answers fall short for various reasons and have probably left readers with more questions. This should handle all future questions related to generic classes in a collection.