从字符串生成类实例并调用构造函数
本文关键字:调用 构造函数 实例 字符串 | 更新日期: 2023-09-27 18:30:13
我正在制作RTS游戏。RTS游戏中的每个单位都可以做一些动作,如巡逻、攻击或构建。在unity中,您可以很容易地手动为C#脚本填充string
和integer
数组。
正因为如此,我决定对任何单元都使用string[] str_actions
数组是最简单的,当单元第一次初始化时,将此数组转换为Action[] actions
。
我可能会这样做:
string className = "Attack"
Assembly assembly = Assembly.Load("Actions");
Type t = assembly.GetType("Actions."+className);
Action action = (Action)Activator.CreateInstance(t);
但这并不能解决两个问题:
- 操作没有接受0个参数的构造函数
className
引用的类不是Action
的子类的可能性
我该如何处理它们?
要回答发布的问题:
-
没关系!使用Activator.CreateInstance:MMSDN的这个重载,您可以传入一个对象[],它将找到最适合的构造函数。不过,拥有一个默认的构造函数是一个好主意,尤其是当您要使用序列化时。
-
你不能"处理"它,因为你可以避免它的发生。但是,如果强制转换失败,您编写的代码将抛出
InvalidCastException
。为了避免这种情况,请使用as
运算符:Action action = Activator.CreateInstance(t) as Action;
现在,如果强制转换无效,
action
将只保留null
,而不是抛出。
现在需要注意的是:Activator.CreateInstance
在C#中很少是正确的选择。通常,您希望使用直接实例化或反序列化。诚然,反序列化利用反射;但所有杂乱的细节都被抽象掉了。
所以我已经想通了。我正在使它成为一个静态方法Action.fromString
。我缺少的是返回ConstructorInfo
对象的Type.GetConstructor
方法。
public static Action fromString(string className, string defName, WorldObject actor)
{
//Get the Assembly (namespace)
Assembly assembly = Assembly.Load("Actions");
//Get the exact class Type
Type t = assembly.GetType("Actions." + className);
//Get the info about constructor (using array literal)
// - for every accepted parameter enter typeof(parameterType)
ConstructorInfo constructor = t.GetConstructor(new Type[] { typeof(string), typeof(WorldObject) });
//Initialise the Type instance
System.Object action = constructor.Invoke(new System.Object[] { defName, actor });
//If it's child of the main class
if (action is Action)
return (Action)action;
//Error otherwise
else
{
Debug.LogError("'" + className + "' is not child of Action!");
return null;
}
}