繁体   English   中英

如何在不使用反射的情况下从类名称创建类的实例?

[英]How to create instance of a class from class name without using reflection?

有什么办法可以实现这样的目标吗?

如果将"Employee"作为参数传递给方法,则它应返回Employee类型的对象。

但是不使用反射。

您可以使用Type.GetType(string)获取该类型的元数据。 但是,这需要该类型的程序集合格名称 ,除非该类型驻留在当前正在执行的程序集中或者是mscorlib.dll的一部分。

然后,您可以使用Activator.CreateInstance(Type)获取实例。

var type = Type.GetType(typeName);
var obj = Activator.CreateInstance(type);

此时, obj的静态类型为System.Object 您将需要继续使用反射来获取实际类型上定义的属性和方法,或者可以将对象视为dynamic对象,假设您在编译时不知道将结果强制转换为哪个类(以及是否已知道,您将跳过整个过程)。


编辑:由于添加了不想使用反射的约束,因此更改了选项。 关于您所支持的内容,代码并不会那么动态 ,您通常需要提前知道想法,但这可能是一件好事,具体取决于您要实现的目标。 您可能只是一个switch语句或具有受支持类型的字典,将名称作为字符串键入。

public object GetInstanceOf(string typeName)
{
    switch (typeName)
    {
        case "Employee": return new Employee();
        case "Manager" : return new Manager();
        case "Owner" : return new Owner();
        // etc
        default: 
            throw new InvalidOperationException("typeName is not supported");
    }
}

请注意,使用这种方法,您预先知道所有受支持的类型。 还有其他方法可以在代码之外预先了解类型(例如,配置,数据),但是通常这些方法会使您回到答案的第一部分。 另请注意,您的退货类型仍然有限。 它必须是所涉及类的通用基本类型或接口。 在我的代码示例中,它是所有类和结构System.Object的通用基本类型。 对您来说,这可能更像是带有Worker基类或IWorker接口的factory 也许Employee是基础,而您的方法是构造它的专门子级。 后两个示例使您可以在编译时访问基本或接口定义的方法和属性。

是的,比您可以借助“ 反思 ”来做的更好

尝试

Employee employee =(Employee)Activator.CreateInstance("Employee"); 

检查@jon skeet答案: 如何从C#中的字符串创建实例?

在没有反射的情况下实例化任意类型

我错了。 看起来,有很多方法可以实例化类型而无需真正的反思。 我将尝试列出所有可以找到的清单。

泛型

根据您要尝试执行的操作,您也许可以执行一种很酷的技术,称为泛型。 您不能在运行时输入类型的任意名称,因此这不一定能完整回答您的问题,但是,如果您知道在编译时想要的类型,那么这将是一个很好的工具。 这不涉及任何形式的反映 ,但是完全是编译时。 这是一个例子:

interface IParsable
{
    bool TryParse(string text);
}

class MyInt : IParsable
{
    public int Value { get; private set; }

    public static MyInt Parse(string text)
    {
        Parser parser = new Parser();
        return parser.Parse<MyInt>(text);
    }
}

class MyFloat : IParsable
{
    public float Value { get; private set; }

    public static MyFloat Parse(string text)
    {
        Parser parser = new Parser();
        return parser.Parse<MyFloat>(text);
    }
}

class Parser
{
    // The "new()" constraint means that T must have a
    // parameterless constructor.
    private T Parse<T>(string text)
        where T : IParsable, new()
    {
        // Even though T isn't actually a type, we can use
        // it as if it were, for the most part.
        T obj = new T();

        // Because we had the IParsable constraint, we can
        // use the TryParse method.
        if (!obj.TryParse(text))
        {
            throw new Exception("Text could not be parsed.");
        }

        return obj;
    }
}

Lambdas字典

感谢Anthony Pegram在这方面的天才(请参阅下面的评论)。 以前,我使用反射进行了此操作,但是由于使用了lambda表达式,他将其固定为可以进行任何反射操作。

static readonly IDictionary<string, Func<object>> Types = new Dictionary<string, Func<object>>()
{
    { "TypeA", () => new TypeA() },
    { "TypeB", () => new TypeB() },
    { "TypeC", () => new TypeC() },
};

// If you're okay with a bit of reflection behind-the-scenes, change "object"
// here to "dynamic", and you won't have to cast down the road.
object void GetInstance(string name)
{
    if (Types.ContainsKey(name))
    {
        return Types[name]();
    }
    else
    {
        return null;
    }
}

预实例化的对象

另一个选择是每次都返回相同的引用。 这完全避免了“真实”的反映。 重用实例的想法有一些重要的含义,取决于您在做什么,这可能是好事也可能是坏事。 这些含义非常有趣,如果使用得当,可能会非常惊人。

如果需要,可以让每种类型实现一个特定的接口,然后强制转换为该接口,而不是返回原始对象。

static readonly IDictionary<string, object> Instances = new Dictionary<string, object>()
{
    { "TypeA", new TypeA() },
    { "TypeB", new TypeB() },
    { "TypeC", new TypeC() },
};

object void GetInstance(string name)
{
    if (!Instances.ContainsKey(name))
    {
        return null;
    }

    return Instances[name];
}

用反射实例化任意类型

您有很多不错的答案,如果您的类型具有无参数构造函数,这些答案将非常有用。 但是,如果没有呢?

const string TYPE = "System.String";
Type type = Type.GetType(TYPE);
if (type == null)
{
    // Type doesn't exist--at least, not in mscorlib or current assembly,
    // or we didn't specify the assembly.
    throw new Exception("Could not find type " + TYPE + ".");
}

// Note the Type array.  These are the types of the parameters that the
// constructor takes.
ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(char), typeof(int) });
if (ctor == null)
{
    // Constructor doesn't exist that takes those parameters.
    throw new Exception("Could not find proper constructor in " + TYPE + ".");
}

// Note the object array.  These are the actual parameters passed to the
// constructor.  They should obviously match the types specified above.
string result = (string)ctor.Invoke(new object[] { 'a', 5 });

您可以使用Activator.CreateInstance()

Employee employee =(Employee)Activator.CreateInstance("Namespace", "Employee");

使用反射@vulkanino表示您将以如下形式结束:

Employee instance = (Employee)Activator.CreateInstance("MyNamespace.Employee, MyAssembly");

希望这对您有所帮助。

使用反射,您可以在程序集中找到类型,无论是正在执行的程序集还是其他已加载的类型(实际上,您都可以按需加载它们)。 在没有指定如何在您的方案中工作的完整示例的情况下,您将使用Activator.CreateInstance的方法来创建找到的对象的实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM