I have two Interfaces, one of them is a generic one, allowing only Types that derive from the second Interface. They look like this:
public interface IProvider<T> where T : IContent
{
T getContent(int i);
void addContent(T content);
}
public interface IContent
{
string whatIAm();
}
Of course my real Interfaces are more complex but it is enought to show what my problem is.
Now i have for each interface a concrete class:
public class Provider : IProvider<FileContent>
{
public FileContent getContent(int i)
{
return null;
}
public void addContent(FileContent content)
{
}
}
public class FileContent : IContent{
public string whatIAm(){
return "FileContent";
}
}
And in my code i want to work with the reference type “IProvider” but the cast goes wrong… Please look at this example:
static void Main(string[] args)
{
Provider p = new Provider(); //works
IProvider<FileContent> pp = p as IProvider<FileContent>; //also works
IProvider<IContent> ppp = pp as IProvider<IContent>; //fails :(
}
ppp is always null. What do i have to change that this cast is working?
Thanks in advance.
The type argument must match exactly.
IProvider<IContent>is a different type thanIProvider<FileContent>, there is no inheritance between them.Imagine you have an
IProvider<IContent> pppfrom yourIProvider<FileContent>and a developer triesppp.addContent(someOtherContentThatIsNoFileContent). That statement is valid forIProvider<IContent>, but it would break type safety, so not allowing such a conversion is the right thing to do.Covariance and Contravariance for generic type parameters allow something like this under certain circumstances, but since your interface uses the type parameter both as in- and output parameter, this won’t apply to it the way it is declared right now.
EDIT: Look at
IEnumerable‘s definition:So you know IEnumerable uses
Tonly as output parameter (you can’t add items, only enumerate them), and theoutkeyword specifies thatTis covariant. So you can doIf you want to do this, you would have to remove the
addmethod from your interface. Same applies for input parameters and theinkeyword on generic type parameters.Your interface would then look like this: