tags:

views:

791

answers:

3

Not entirely sure how to phrase the question, because it's a "why doesn't this work?" type of query.

I've reduced my particular issue down to this code:

public interface IFoo
{
}

public class Foo : IFoo
{
}

public class Bar<T> where T : IFoo
{
    public Bar(T t)
    {
    }

    public Bar()
        : this(new Foo()) // cannot convert from 'Foo' to 'T'
    {
    }
}

Now, the generic type T in the Bar<T> class must implement IFoo. So why does the compiler give me the error in the comment? Surely an instance of Foo is an IFoo, and can therefore be passed around as a representative of the generic type T?

Is this a compiler limitation or am I missing something?

+2  A: 

If you create a class Baz and then the generic type Bar baz = new Bar(), new Foo() as defined by your constructor overload, would not be of type T, in this case Baz.

Timothy Carter
+1 Thanks yshuditelu. I'm giving Andrew the accepted answer since his is a little more complete with the code samples (and you were only 8 seconds apart). :)
Matt Hamilton
Agreed (and thanks).
Timothy Carter
+8  A: 

You could also have a Fiz that implements IFoo that is not related to Foo in any other way:

public interface IFoo
{
}

public class Foo : IFoo
{
}

public class Fiz : IFoo
{
}

Foo foo = new Foo();
Fiz fiz = foo; // Not gonna compile.

What you want is probably more like:

public class Bar<T> where T : IFoo, new()
{
    public Bar(T t)
    {
    }

    public Bar()
        : this(new T()) 
    {
    }
}

So you can have

Bar<Foo> barFoo = new Bar<Foo>();
Bar<Fiz> barFiz = new Bar<Fiz>();
Andrew Kennan
This is sweet as I didn't know you could the new T() thing, you just saved my life in a project I am working on. Cheers :)
Nathan W
A: 

It's because if you create a class:

public class Fred : IFoo
{
}

And then instantiate Bar<T> like this:

var bar = new Bar<Fred>();

Then it violates the constraints of the class as a Foo is not a Fred which is the current T.

You can force it to compile by putting the cast sequence (T)(IFoo)new Foo() in the constructor, but you'll get an InvalidCastException at runtime if the actual type of T is not assignable from Foo.

Greg Beech