[英]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;
}
}
感谢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.