我有一个类似下面的代码结构
interface IAnimal
{
string name;
int Age;
}
class Tiger : IAnimal
{
public string name;
public int Age;
}
class Dog : IAnimal
{
public string name;
public int Age;
}
扩展类位于
之下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;
}
}
错误:无法将Tiger隐式转换为TAnimal
为什么编译器无法将Tiger(此类实现的IAnimal)转换为TAnimal。使用通用约束时,这似乎是一个问题。
虽然下面的代码工作正常..
IAnimal myTiger = new Tiger();
答案 0 :(得分:4)
因为TAnimalType
可以是任何动物类型,甚至Dog
。如果有人致电ConvertTo<Dog>()
,您编写的代码将如下所示:
public static Dog ConvertTo(this Animal animal)
{
Dog concreteAnimal;
if (animal.Name == "tom")
{
concreteAnimal = new Tiger(); // compiler error at this line
}
return concreteAnimal;
}
用户要求Dog
,但您尝试分配Tiger
并将其返回。您无法做到这一点,因为Tiger
不是Dog
。
答案 1 :(得分:4)
你有:
class Tiger : IAnimal
和其他地方的约束:
where TAnimalType : IAnimal
然后你去:
TAnimalType concreteAnimal;
// ...
concreteAnimal = new Tiger(); // compiler error at this line
但是我们(和编译器)知道的是Tiger
和TAnimalType
都实现了相同的接口。 这并不意味着Tiger
和TAnimalType
之间存在任何关系!
例如,TAnimalType
可以合法地成为Dog
。在这种情况下,您会将Tiger
放入Dog
变量concreteAnimal
。这是不允许的。
答案 2 :(得分:1)
为什么编译器无法将Tiger(此类实现的IAnimal)转换为TAnimal。使用通用约束时,这似乎是一个问题。
我认为其他答案已解决为什么您的代码无法按照书面形式工作。但是,这是一个如何完成我认为之后的例子。使用此扩展方法,调用者可以明确说明要将*转换为* IAnimal
的实现。 TOut
参数受约束,因此它具有无参数构造函数,因此我可以创建它的新实例并复制原始animal
实例中的值。如果有的话,这可能会给你一些思考的食物。希望有所帮助!
*单词&#34;转换&#34;这里有点误导。我们绝对不会在这里转换任何东西。
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; }
}