【问题标题】:Call a function on AddComponent( string variable )在 AddComponent( 字符串变量 ) 上调用函数
【发布时间】:2013-07-31 11:50:47
【问题描述】:
Type thistype = stringVar.GetType();
thistype myScript = gameObject.AddComponent(stringVar);

myScript.runCustomFunction();

这不起作用,我相信这是因为如果我在编译时(而不是运行)不知道变量类型,我无法转换为变量类型,因此我无法直接访问我的组件刚刚添加。

我有一个 gameItem 类,它从另一个脚本中提取其默认值,然后将它们放入字典中。基于字典条目“functionScript”,“myScript”,我需要将 myScript 附加到对象,然后传递一些字典条目。

另外,我可能真的效率低下,并在 myScript 类上向 item 类询问其变量,我宁愿避免这样做。

【问题讨论】:

  • 好的,所以我无法准确地理解您要完成的工作。 stringVar 的值类似于 "myScript" 并且您需要能够根据名称提取适当的具体类型?
  • 字符串 stringVar 等于“myScript”(或任何其他脚本名称,取决于默认项值设置传递的字符串)。我需要使用该字符串添加一个名为 myScript 的组件脚本(或任何其他名称,无论传递什么),然后运行一个函数/将一些变量传递给新添加的组件。
  • 但是该值是否对应于具体类型?您显然对此有所了解,否则您不会尝试致电runCustomFunction。您的所有类型都继承自同一个底层基类吗?还是实现一个接口?
  • 感谢您的快速回复! - 我将尝试澄清我正在尝试做的事情:我有一个 gameItem 类,它存储各种变量(项目类型、伤害、冷却时间等)。如果手动覆盖关闭,我会运行一个函数来设置 gameItem 类的所有默认值(从字典中提取)。一个变量是一个名为 gameItemScript 的字符串。调用 AddWeaponScript(string gameItemScript) 方法时,需要添加名为 gameItemScript 的组件,然后在该组件上设置一些变量。

标签: c# dynamic unity3d unity-components


【解决方案1】:

System.Type 是一个实际类型,与System.Int32System.Guid 非常相似。您不能在代码中使用变量作为静态标识符,因为编译器不知道该类型是什么。

认为您正在尝试做的是根据其名称构造一个具体类型。

你可以使用Activator.CreateInstance来做到这一点,只要你知道类型名和程序集名。

var typeName = "MyType";
var myType = Activator.CreateInstance("MyAssembly", typeName); 

您也可以使用 dynamic 关键字让 DLR 为您处理繁重的工作。

dynamic myType = Activator.CreateInstance("MyAssembly", typeName);
myType.runCustomFunction();

如果您的类型继承自公共基类型或实现接口,则可以将其强制转换为该类型并调用您的方法。

//Safe cast as base type
var myType = Activator.CreateInstance("MyAssembly", typeName) as BaseType;

//Or safe cast as interface
var myType = Activator.CreateInstance("MyAssembly", typeName) as IMyType;

但是,如果您的类型不是从已知类型继承的,但您知道它们都有一个名为 runCustomFunction 的方法并且您不想使用 dynamic,那么您可以对 invoke that method 使用一点反射.

//Create the System.Type using assembly qualified name
var typeName = "MyType";
var assemblyQualifiedName = String.Format("MyAssembly.{0}", typeName);
var myType = Type.GetType(assemblyQualifiedName);

//Call activator overload, but `instance` is a System.Object
var instance = Activator.CreateInstance(myType);

//Use reflection to invoke the method
myType.InvokeMember(
   "runCustomFunction", //member name
   BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static,
   null, //default binder
   instance, //actual instance to invoke method on
   null //no arguments so we use null
);

如您所见,让您的所有类型都从某个基类继承或实现一个接口要容易得多,但如果您想以艰难的方式做到这一点,您当然可以使用反射:)

【讨论】:

  • 大量道具,用于花时间涵盖所有可能性。但是,我正在尽力自己寻找答案 - 在这种情况下,“MyAssembly”代表什么?
  • @DS 我还在列表中添加了dynamic 选项。差点忘了这件事。在这种情况下,MyAssembly 表示定义类型的程序集的名称。通常这与您的项目名称相同,但您可以检查属性以确定。例如,如果我的项目名为 JoshStuff,那么我的程序集名称很可能是相同的。
  • 供将来参考 - Unity3d 的组装参考似乎是“Assembly-CSharp”。 var typeName = scriptName; var myType = Activator.CreateInstance("Assembly-CSharp",typeName); myType itemScript = gameObject.AddComponent(scriptName); 该代码返回“找不到类型或命名空间名称‘myType’。您是否缺少 using 指令或程序集引用?”
  • @DigitalSalmon 这是您创建的自定义类型吗?您的项目中有一个吗?
  • 我不确定在这种情况下我是否完全理解类型的原理。通常,如果要将脚本组件添加到对象,“类型”只是脚本名称。按照这个逻辑,是的,Type 是自定义类型。
猜你喜欢
  • 2011-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 2018-06-21
  • 2015-11-05
  • 2017-11-29
  • 2010-11-10
相关资源
最近更新 更多