是否允许在另一个泛型方法中调用泛型方法?

时间:2017-12-30 16:46:49

标签: c# generics unity3d refactoring

我正在与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]

2 个答案:

答案 0 :(得分:5)

问题在于......

void Harvest<T>(){
    gameObject.GetComponent<T>().Harvest();
}

... C#编译器不知道具体类型T将是什么。因此,它不能知道方法Harvest可用,也不知道它的确切声明(它是否返回voidbool或其他东西?它是否有可选参数? )。因为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}}类型实例的方法,从而导致运行时错误。