ana*_*lov 4 c# generics casting interface
我有一个简单的接口,两个类实现它:
public interface IMovable { }
public class Human : IMovable { }
public class Animal : IMovable { }
Run Code Online (Sandbox Code Playgroud)
以下泛型方法导致编译时错误: Cannot convert type 'Human' to 'T'
public static T DoSomething<T>(string typeCode) where T : class, IMovable
{
if (typeCode == "HUM")
{
return (T)new Human(); // Explicit cast
}
else if (typeCode == "ANI")
{
return (T)new Animal(); // Explicit cast
}
else
{
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
但是当使用as关键字时,一切都很好:
public static T DoSomething<T>(string typeCode) where T : class, IMovable
{
if (typeCode == "HUM")
{
return new Human() as T; // 'as'
}
else if (typeCode == "ANI")
{
return new Animal() as T; // 'as'
}
else
{
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
为什么as工作但是明确的演员没有?
简短的回答是,因为T不一定是正确的类型.编译器真的试图在这里帮助你,因为你正在做一些可能在运行时很容易失败的东西.
例如,考虑以下情况:
var result = DoSomething<Human>("ANI");
Run Code Online (Sandbox Code Playgroud)
更长的答案是,你根本不应该投.转换表明您的OOP设计存在问题,使用泛型时尤其错误:实际上,您失去了泛型的全部要点.泛型应该允许您创建一个抽象实际类型的"模板",让您担心算法本身而不是具体类型.
在这种情况下,您可能根本不需要泛型.你的方法基本上是一种不太安全的方法:
public static T DoSomething<T>() where T : new()
{
return new T();
}
Run Code Online (Sandbox Code Playgroud)
或这个:
public static IMovable DoSomething(string typeCode)
{
if (typeCode == "HUM")
return new Human();
if (typeCode == "ANI")
return new Animal();
return null;
}
Run Code Online (Sandbox Code Playgroud)
为了使编译器静音,您还可以添加一个中间强制转换,告诉编译器您已经执行了额外的步骤以指示您确实要以这种方式强制转换:例如,使用
(T)(object)new Human()
Run Code Online (Sandbox Code Playgroud)
要么
(T)(IMovable)new Human()
Run Code Online (Sandbox Code Playgroud)
虽然从原来的代码转换IMovable到T比原始代码更安全,并且转换object为T甚至更不安全,但它们都会通过编译.但这不是您的潜在问题的解决方案,这与设计相关.
使用您的代码,完全可以调用DoSomething<Animal>,然后您就可以了(Animal)new Human().
这在生物学上是正确的,但你的模型不允许它.
你真的需要仿制药吗?也许你只想IMovable在这种情况下返回.