【问题标题】:Calling member functions of dynamic objects调用动态对象的成员函数
【发布时间】:2014-02-20 23:48:40
【问题描述】:

我有以下代码。

GameObject target;
dynamic script;
script = target.GetComponent("ScriptName");
script.changeState();

虽然我正在使用 unity3d 工具进行游戏开发,但我觉得这更多地涉及到一个通用的 c# 问题。在代码中,我正在获取一个对象,该对象是链接到另一个游戏对象的脚本。我的目标是调用属于“目标”的脚本的 changeState() 函数。这会产生错误,因为它无法确定 changeState() 是否属于动态变量“脚本”。是否有任何选项可以关闭它(类似于#define pragma strict)?还有其他解决方法吗?

注意:附加到该脚本引用的 GameObject 的脚本具有 changeState() 函数的实现。

【问题讨论】:

  • 可以添加完整的错误文本吗?
  • @GuruStron 内部编译器错误。有关更多信息,请参阅控制台日志。输出为:错误 CS0518:未定义或导入预定义类型“System.Runtime.CompilerServices.CallSite”
  • 这是编译时错误:Compiler Error CS0518。不会是script缺少任何方法造成的,因为它在运行时解析
  • @GuruStron 我删除了我提到的那段代码,我的程序没有错误。
  • 这个问题似乎没用。您使用的 GetComponent 形式表明您使用的是动态的,因为您不知道自己在做什么。你能解释一下为什么这可能不是真的吗?

标签: c# unity3d


【解决方案1】:

你应该在这里使用一个接口,因为你可以换出的所有潜在脚本都包含方法 changeState() 将它们绑定到一个接口来表达它。

这为您提供了更多的类型安全性和更好的重构,而不是使用魔术字符串。它还为您提供了一个很好的错误检查点。

GameObject target;
InterfaceType script;
script = target.GetComponent("ScriptName") as InterfaceType;

if(script != null)
{
    script.changeState();
}

【讨论】:

    【解决方案2】:

    Internal compiler error. See the console log for more information. output was:error CS0518: The predefined type 'System.Runtime.CompilerServices.CallSite' is not defined or imported.

    你是在引用 System.Core.dll 吗?

    Compiler Error CS0518

    【讨论】:

    • 是的 mscorlib.dll 存在于参考文献中。我认为这与使用动态有关,我无法理解。
    • 感谢您的回复。无论如何,我找到了解决方案并发布了它。
    【解决方案3】:

    我不熟悉 GameObject,但也许你可以这样做:

    GameObject target;
    var script = target.GetComponent("ScriptName") as GameObject;
    if (script != null)
    {
        script.changeState();
    }
    

    【讨论】:

    • “as”关键字仅用于严格输入。除了 GetComponent() 检索 UnityEngine.Component。如果使用“as GameObject”,则检索 UnityEngine.GameObject。所以,上面的代码是行不通的。
    【解决方案4】:

    直接来自documentation

    var script = gameObject.GetComponent(FooTest); //note the lack of quotes
    script.FooTestMethod();  //and method unique to FooTest
    

    如果组件不存在,Unity 会报错。

    如果你真的坚持使用基于GetComponent的字符串:

    var script = gameObject.GetComponent("FooTest") as FooTest;
    script.FooTestMethod();
    

    【讨论】:

    • 我认为您没有清楚地理解我的问题。问题是我不知道附加到我的游戏对象“目标”的脚本类型。 “目标”可以是任何游戏对象,我将其拖放到 GUI 中此脚本的游戏对象字段中。因此,我不能使用 GetComponent(FooTest),因为它特定于 FooTest 脚本,它仅附加到一个游戏对象。如果我想拖放另一个游戏对象,那么每次拖动不同的对象时都必须更改那条线。
    • 在下面查看我的解决方案,你就会明白我到底想要什么。
    • @user854617 'ScriptName' 不是变量名,它是附加的 MonoBehaviour 组件的名称。如果您已经知道ScriptName,那么您已经知道组件类型并且不需要成员调用。
    • 在您的代码中:var script = gameObject.GetComponent("FooTest") as FooTest; script.FooTestMethod(); 假设我想在运行时将“脚本”类型转换为 FooTest(在“as”关键字之后)的部分更改为其他脚本的名称,我该怎么做是吗?
    • You use polymorphism 并使用ChangeState() 创建一个父类。我并不是说你的答案不起作用,我只是想指出,在多个组件上调用相同的方法有很多更简单(也更有效)的方法。
    【解决方案5】:

    所以这是我自己的问题的解决方案。可以使用“对象”类型代替动态类型。这是我的代码:

    object script = target.GetComponent("ScriptName");
    Type scriptType = script.GetType();
    object res = scriptType.InvokeMember("changeState", BindingFlags.InvokeMethod,
      null, script, null);
    

    InvokeMember() 在编译期间不解析对象类型的成员函数。不要忘记包含“System.Reflection”。希望这对某人有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-02
      • 2014-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多