I have the following classes and interfaces:
public interface IThing
{
string Name { get; }
}
public class Thing : IThing
{
public string Name { get
The compiler is stumbling over the conversion from MyThingConsumer
to ThingConsumer<T>
even though T:IThing
and MyThingConsumer:Thingconsumer<Thing>
and Thing:IThing
. Which is quite a few hoops for it to jump through!
The code works if you use return new MyThingConsumer() as ThingConsumer<T>;
instead of a direct cast. You know the result will never be null
, and the compiler is happy because it is guaranteed a return value of the right type at runtime.
Edit: Here is the full code I used for testing (in Snippy):
public interface IThing
{
string Name { get; }
}
public class Thing : IThing
{
public string Name { get; set; }
}
public abstract class ThingConsumer<T> where T : IThing
{
public string Name { get; set; }
}
public class MyThingConsumer : ThingConsumer<Thing>
{
}
public static class ThingConsumerFactory<T> where T : IThing
{
public static ThingConsumer<T> GetThingConsumer()
{
if (typeof(T) == typeof(Thing))
{
return new MyThingConsumer() as ThingConsumer<T>;
}
else
{
return null;
}
}
}
...
var thing = ThingConsumerFactory<Thing>.GetThingConsumer();
Console.WriteLine(thing);
If you make ThingConsumer<T>
an interface rather than an abstract class, then your code will work as is.
public interface IThingConsumer<T> where T : IThing
{
string Name { get; set; }
}
Edit
One more change needed. In ThingConsumerFactory
, cast back to the return type IThingConsumer<T>
:
return (IThingConsumer<T>)new MyThingConsumer();
You need to define your class like this I believe:
public class MyThingConsumer<Thing> : ThingConsumer
The reason is that ThingConsumer
is already typed in its definition with this: where T : IThing
Now, you can make the call return new MyThingConsumer<T>();
.
This should in turn match the expected return type of ThingConsumer<T>
EDIT
Sorry for the confusion, here is what should work:
public class MyThingConsumer<T> : ThingConsumer<T> where T : IThing
and
return new MyThingConsumer<T>();