Built-in Common .NET 4.0 Interfaces

I have two interfaces, one of which is common, allowing only types that come from the second interface to be used. 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 complicated, but it’s enough to show that my problem. Now I have a specific class for each interface:

 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 does not work correctly ... 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 always zero. What do I need to change for this actor to work? Thanks in advance.

+4
source share
3 answers

The type argument must match exactly. IProvider<IContent> is a different type than IProvider<FileContent> , there is no inheritance between them.

Imagine you have an IProvider<IContent> ppp from your IProvider<FileContent> , and the developer is trying ppp.addContent(someOtherContentThatIsNoFileContent) . This operator is valid for IProvider<IContent> , but it violates type safety, therefore, such a conversion cannot be allowed.

Covariance and contravariance for type type parameters allow something similar under certain circumstances, but since your interface uses the type parameter as an output parameter, it will not apply to it as it is declared right now.

EDIT: Look at the IEnumerable definition:

 public interface IEnumerable<out T> 

So, you know that IEnumerable uses T only as an output parameter (you cannot add elements, just list them), and the out keyword indicates that T is covariant. So you can do

 IEnumerable<String> strings = new List<String>(); IEnumerable<Object> objects = strings; 

If you want to do this, you will have to remove the add method from your interface. The same applies to input parameters and the in keyword for type parameters.

Your interface will now look like this:

 public interface IProvider<out T> where T : IContent { T getContent(int i); } 
+6
source

This is not a general way of working in C #. A generalization of IProvider<FileContent> not a subtype of IProvider<IContent> .

+3
source

You wrote

 Provider p = new Provider(); //works IProvider<FileContent> pp = p as IProvider<FileContent>; //also works IProvider<IContent> ppp = pp as IProvider<IContent>; //fails :( 

Suppose all three of them work. Then one could write the following:

 ppp.addContent(new NonFileContent()); 

where NonFileContent is a class that implements IContent but not obtained from FileContent .

Now imagine what happens on the next call:

 FileContent fc = pp.getContent(0); 

The returned object must be returned. However, this is an instance of NonFileContent , not FileContent . Therefore, returning this object from a method whose return value is an instance of FileContent is not possible; therefore, the compiler does not consider it compatible with pp and ppp compatible with the destination.

+1
source

All Articles