Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open generic interface types of open implementation don't equal interface type?

Here's a test that should, in my opinion be passing but is not.

[TestMethod]
public void can_get_open_generic_interface_off_of_implementor()
{
    typeof(OpenGenericWithOpenService<>).GetInterfaces().First()
        .ShouldEqual(typeof(IGenericService<>));
}
public interface IGenericService<T> { }
public class OpenGenericWithOpenService<T> : IGenericService<T> { }
  1. Why does this not pass?
  2. Given Type t = typeof(OpenGenericWithOpenService<>) how do I get typeof(IGenericService<>)?

I'm generally curious, but if you're wondering what I'm doing, I'm writing a Structuremap convention that forwards all interfaces implemented by a class to the implementation (as a singleton).

like image 872
George Mauer Avatar asked Apr 20 '10 20:04

George Mauer


People also ask

Can a generic implement an interface?

Only generic classes can implement generic interfaces. Normal classes can't implement generic interfaces.

What is a generic interface?

Generic Interfaces in Java are the interfaces that deal with abstract data types. Interface help in the independent manipulation of java collections from representation details. They are used to achieving multiple inheritance in java forming hierarchies. They differ from the java class.

When would you use a generic interface?

It's often useful to define interfaces either for generic collection classes, or for the generic classes that represent items in the collection. To avoid boxing and unboxing operations on value types, it's better to use generic interfaces, such as IComparable<T>, on generic classes.

Can we have generic interface in C#?

You can declare variant generic interfaces by using the in and out keywords for generic type parameters. ref , in , and out parameters in C# cannot be variant. Value types also do not support variance. You can declare a generic type parameter covariant by using the out keyword.


Video Answer


1 Answers

OpenGenericWithOpenService<T> doesn't implement just an arbitrary IGenericService<> - it implements IGenericService<T> for the same T as the class.

The best way to show this is to change the class slightly:

public class OpenGenericWithOpenService<T1, T2> : IGenericService<T1> {}

Now it's important that when you ask that for the interfaces it implements, you know that you can convert to IGenericService<T1> but (coincidences aside) not IGenericService<T2> or any other implementation.

In other words, it's not entirely open - it's pinned down to the same type argument that the class has.

I've never been very good with the generics terminology, but I hope you see what I mean. IGenericService<> is a type waiting to be given a type argument; in this case you've got the type argument - it just happens to be another type parameter!

Here's a test which will pass:

[TestMethod]
public void can_get_open_generic_interface_off_of_implementor()
{
    Type[] typeParams = typeof(OpenGenericWithOpenService<>).GetGenericArguments();
    Type constructed = typeof(IGenericService<>).MakeGenericType(typeParams);
    typeof(OpenGenericWithOpenService<>).GetInterfaces().First()            
        .ShouldEqual(constructed);
}

If you change the class to implement (say) IGenericService<int> instead, it will fail.

like image 147
Jon Skeet Avatar answered Oct 21 '22 02:10

Jon Skeet