More generics gotchas, argh!
I have been working on .NET 2.0 for a long time now, generics still manage to trip me.
Consider this piece of code:
public interface IFoo<TFromInterface> { } public class Foo<TFromClass> : IFoo<T> { } [Test] public void More_Generics_Gotcha() { Assert.AreEqual(typeof(IFoo<>), typeof(Foo<>).GetInterfaces()[0]); }
This test fails. the returned System.Type instance is a IFoo<TFromClass>, which is an unbounded generic parameter, but not the same as IFoo<> itself. Now I need to apologize for Windsor, it wasn't its fault all along.
Comments
I've found this post to be quite helpful:
http://blogs.msdn.com/dinesh.kulkarni/archive/2005/09/09/463001.aspx
I was a little puzzled by it too on the first time, but when I ventured deeper into generics I realized this really is very logical. In fact, it wouldn't make sense any other way.
See, when you say:
public class Foo<T> : IFoo<T>
The first <T> means "I'm declaring a generic parameter, let's call it T". But the second one means "Now I'm USING said generic parameter, in effect saying that any type constructed from Foo<T> will implement IFoo<T> for the same T."
The fact that you used the same name (T) for the generic parameter declaration on IFoo is irrelevant; inside the scope of the generic class, T refers to the already-declared generic parameter.
If IFoo<T> had IFoo<> in its interface map, nothing would work. That's more apparent when you consider stuff like "public class Thingy<T> : IFoo<IEnumerable<T>>". Here it's very obvious that you want the implemented interface to use the unbound generic parameter T, so that when you construct a concrete type out of that generic type, using System.Int32 for T, it'd implement IFoo<IEnumerable<int>>. .
If that's any comfort, you can still do:
Assert.AreEqual(
Avish,
Yes, that was what I ended up doing. The problem is that it took me a long time to get to the point of "Oh, so that is it"
Incidentally, another way to make it pass is to specify any generic param:
Assert.AreEqual(typeof(IFoo<Bar>), typeof(Foo<Bar>).GetInterfaces()[0]);
or :
Assert.IsTrue(typeof(IFoo<Bar>).IsAssignableFrom(typeof(Foo<Bar>)));
Should be "public class Foo<TFromClass> : IFoo<TFromClass> { }".
Comment preview