Reputation: 474
I have a code structure like below
interface IAnimal
{
string name;
int Age;
}
class Tiger : IAnimal
{
public string name;
public int Age;
}
class Dog : IAnimal
{
public string name;
public int Age;
}
extension class is below
public static class AnimalExtension
{
public static TAnimalType ConvertTo<TAnimalType>(this Animal animal) where TAnimalType : IAnimal
{
TAnimalType concreteAnimal;
if (animal.Name == "tom")
{
concreteAnimal = new Tiger(); // compiler error at this line
}
return concreteAnimal;
}
}
Error : Can't implicitly convert Tiger to TAnimal
Why is the compiler not able to convert Tiger(this class implemented IAnimal) to TAnimal. This seems to be a problem while using generic constraints.
While the below code works fine..
IAnimal myTiger = new Tiger();
Upvotes: 2
Views: 85
Reputation: 10608
Why is the compiler not able to convert Tiger(this class implemented IAnimal) to TAnimal. This seems to be a problem while using generic constraints.
I think the other answers have addressed why your code won't work as written. However, here's an example of how to accomplish what I think you're after. With this extension method, the caller explicitly states which implementation of IAnimal
they want to convert* to. The TOut
parameter is constrained so that it has a parameterless constructor, so I can create a new instance of it and copy over the values from the original animal
instance. If anything, this might give you some food for thought. Hope that helps!
* The word "convert" is a little misleading here. We're definitely not converting anything here.
class Program
{
static void Main(string[] args)
{
Dog d = new Dog { Age = 37, Name = "Nick" };
Tiger t = d.ConvertTo<Dog, Tiger>();
Debug.Assert(t.Name == d.Name);
Debug.Assert(t.Age == d.Age);
}
}
static class AnimalExtension
{
public static TOut ConvertTo<TIn, TOut>(this TIn animal)
where TIn : IAnimal
where TOut : IAnimal, new()
{
TOut convertedAnimal = new TOut
{
Age = animal.Age,
Name = animal.Name
};
return convertedAnimal;
}
}
interface IAnimal
{
string Name { get; set; }
int Age { get; set; }
}
class Tiger : IAnimal
{
public int Age { get; set; }
public string Name { get; set; }
}
class Dog : IAnimal
{
public int Age { get; set; }
public string Name { get; set; }
}
Upvotes: 1
Reputation: 62002
You have:
class Tiger : IAnimal
and elsewhere a constraint:
where TAnimalType : IAnimal
and then you go:
TAnimalType concreteAnimal;
// ...
concreteAnimal = new Tiger(); // compiler error at this line
But all we (and the compiler) know is that both Tiger
and TAnimalType
implement the same interface. That does not imply any relation what so ever between Tiger
and TAnimalType
themselves!
For example TAnimalType
could legally be a Dog
. In that case you would be putting a Tiger
into the Dog
variable concreteAnimal
. That is not allowed.
Upvotes: 4
Reputation: 6684
Because TAnimalType
could be any animal type, even Dog
. If someone called ConvertTo<Dog>()
, the code you've written would look like this:
public static Dog ConvertTo(this Animal animal)
{
Dog concreteAnimal;
if (animal.Name == "tom")
{
concreteAnimal = new Tiger(); // compiler error at this line
}
return concreteAnimal;
}
The user asked for a Dog
, but you're trying to assign a Tiger
and return it. You can't do that because a Tiger
is not a Dog
.
Upvotes: 4