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

C# 从字符串生成类实例并调用构造函数,c#,reflection,C#,Reflection,我正在做一个RTS游戏。RTS游戏中的每个单位都可以做一些动作,比如巡逻、攻击或建造。在unity中,您可以轻松地为C#脚本手动填充字符串和整数数组 正因为如此,我决定最简单的方法是为所有单元设置一个string[]str\u actions数组,当单元首次初始化时,将该数组转换为Action[]actions 我大概可以: 但这并不能解决两个问题: 操作没有接受0个参数的构造函数 className引用的类不是Action 我该如何处理它们呢?所以我已经想好了。我正在使它成为一个静态方法Act

我正在做一个RTS游戏。RTS游戏中的每个单位都可以做一些动作,比如巡逻、攻击或建造。在unity中,您可以轻松地为C#脚本手动填充
字符串
整数
数组

正因为如此,我决定最简单的方法是为所有单元设置一个
string[]str\u actions
数组,当单元首次初始化时,将该数组转换为
Action[]actions

我大概可以:

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

  • 操作没有接受0个参数的构造函数
  • className
    引用的类不是
    Action

  • 我该如何处理它们呢?

    所以我已经想好了。我正在使它成为一个静态方法
    Action.fromString
    。我缺少的是返回
    ConstructorInfo
    对象的方法

        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;
            }
        }
    

    要回答张贴的问题,请执行以下操作:

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

  • 你不能“处理”它,因为你可以避免它的发生。但是,如果强制转换失败,您编写的代码将抛出一个
    InvalidCastException
    。要避免这种情况,请使用
    as
    操作符:

    Action action = Activator.CreateInstance(t) as Action;
    
    现在,如果强制转换无效,
    action
    将只保留
    null
    ,而不是抛出


  • 现在需要注意的是:
    Activator.CreateInstance
    在C#中很少是正确的选择。通常,您希望使用直接实例化或反序列化。诚然,反序列化利用了反射;但所有混乱的细节都被抽象掉了

    不要使用反射;使用继承。如果您愿意,可以使用序列化来存储列表。我使用的是继承。每个动作都是抽象类动作的子动作。但是序列化——否则如何从字符串中获取类实例呢?当然,但它会为您进行所有这些反射,您不必担心这两个问题(假设没有人手动修改文件);或者这就是你所担心的?也许有一种方法可以按照你的建议去做,但我对C#不熟悉,我真的只想通过类名实例化类。如果没有找到构造函数,我是否也会得到
    null
    ?@TomášZato根据文档,这会引发
    MissingMethodException
    。你需要试一下/抓住它。
    Action action = Activator.CreateInstance(t) as Action;