簡體   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