从字符串生成类实例并调用构造函数

本文关键字:调用 构造函数 实例 字符串 | 更新日期: 2023-09-27 18:30:13

我正在制作RTS游戏。RTS游戏中的每个单位都可以做一些动作,如巡逻攻击构建。在unity中,您可以很容易地手动为C#脚本填充stringinteger数组。

正因为如此,我决定对任何单元都使用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);

但这并不能解决两个问题:

  1. 操作没有接受0个参数的构造函数
  2. className引用的类不是Action的子类的可能性

我该如何处理它们?

从字符串生成类实例并调用构造函数

要回答发布的问题:

  1. 没关系!使用Activator.CreateInstance:MMSDN的这个重载,您可以传入一个对象[],它将找到最适合的构造函数。不过,拥有一个默认的构造函数是一个好主意,尤其是当您要使用序列化时。

  2. 你不能"处理"它,因为你可以避免它的发生。但是,如果强制转换失败,您编写的代码将抛出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;
        }
    }