[英]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.