我正在与Unity进行RTS游戏。我的游戏中有许多类型的资源,例如树,农场。每个资源都是一个GameObject,它有自己的主脚本来控制它。
实施例。我想收获一棵树,我称之为。
gameObject.GetComponent<Tree>().Harvest();
如果我想收获农场,我会调用相同的脚本,但要更改&#34; Tree&#34;到&#34;农场&#34;这很好,但代码将被复制。所以我通过使用这样的泛型方法来抽象它。
void Harvest<T>(){
gameObject.GetComponent<T>().Harvest();
}
但C#编译器不允许我这样做。我想知道是否可以定义使用泛型方法的泛型方法?如果没有,有没有办法像这样抽象我的代码?谢谢。
错误讯息:
&#39; T&#39;不包含&#39; Harvest&#39;的定义没有延伸方法&#39; Harvest&#39;接受第一个类型&#39; T&#39;可以找到(你错过了使用指令或程序集引用吗?)[Assembly-CSharp]
答案 0 :(得分:5)
问题在于......
void Harvest<T>(){
gameObject.GetComponent<T>().Harvest();
}
... C#编译器不知道具体类型T
将是什么。因此,它不能知道方法Harvest
可用,也不知道它的确切声明(它是否返回void
或bool
或其他东西?它是否有可选参数? )。因为C#是一种强类型语言,所以必须在编译时知道它。这使您确信一切都会在运行时顺利进行。
解决方案是通过指定泛型类型约束为编译器提供提示。为此,您必须声明一个接口,并让具有Harvest
方法的组件实现它。
public interface IHarvestable
{
void Harvest();
}
使用以下命令指定约束:
void Harvest<T>() where T : IHarvestable
{
gameObject.GetComponent<T>().Harvest();
}
在您控制基类的其他情况下,您还可以在基类中声明所需的方法(可能是抽象的),并在generic type constraint而不是接口中指定基类。 / p>
答案 1 :(得分:2)
为使用Harvest()
的所有对象定义一个接口,然后定义T扩展该接口:
public interface IHarvestable
{
void Harvest();
}
// In your class:
void Harvest<T>() where T: IHarvestable
{
gameObject.GetComponent<T>().Harvest();
}
BAD替代方案(仅作为&#34; hacky&#34;提及答案,因为C#支持此功能 - 请勿在实践中使用它):如果您想跳过时间检查,可以使用{{1} }:
dynamic
请注意,这是一种不好的做法,导致方法调用在运行时解析,从而导致性能下降并使代码更容易出错。例如,编译器将允许使用未实现dynamic harvestable = gameObject.GetComponent<T>();
harvestable.Harvest();
的{{1}}类型实例的方法,从而导致运行时错误。