[c#] 從Type獲取新的對象實例



Answers

ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

Activator類有一個通用的變體,這使得這一點更容易:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Question

在編譯時,人們可能並不總是知道對象的類型,但可能需要創建一個類型的實例。 你如何從Type獲得一個新的對象實例?




它非常簡單。 假設您的類名是Car ,並且命名空間是Vehicles ,然後將參數傳遞為Vehicles.Car ,它返回Car類型的對象。 像這樣,你可以動態地創建任何類的任何實例。

public object GetInstance(string strNamesapace)
{         
     Type t = Type.GetType(strNamesapace); 
     return  Activator.CreateInstance(t);         
}

如果您的完全限定名稱 (即本例中的Vehicles.Car )位於另一個程序集中,則Type.GetType將為空。 在這種情況下,您可以遍歷所有程序集並找到Type 。 為此,您可以使用下面的代碼

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

你可以通過調用上述方法來獲取實例。

object objClassInstance = GetInstance("Vehicles.Car");



此問題的一個實現是嘗試調用Type的無參數構造函數:

public static object GetNewObject(Type t)
{
    try
    {
        return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return null;
    }
}

這是同樣的方法,包含在一個通用的方法中:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}



鑑於這個問題,激活器將在有無參數ctor的情況下工作。 如果這是一個約束考慮使用

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()



如果你想使用默認構造函數,那麼使用前面介紹的System.Activator的解決方案可能是最方便的。 但是,如果類型缺少默認構造函數,或者您必須使用非默認構造函數,則選項是使用反射或System.ComponentModel.TypeDescriptor 。 在反射的情況下,知道類型名稱(使用其名稱空間)就足夠了。

使用反射的示例:

ObjectType instance = 
    (ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(
        typeName: objectType.FulName, // string including namespace of the type
        ignoreCase: false,
        bindingAttr: BindingFlags.Default,
        binder: null,  // use default binder
        args: new object[] { args, to, constructor },
        culture: null, // use CultureInfo from current thread
        activationAttributes: null
    );

使用TypeDescriptor示例:

ObjectType instance = 
    (ObjectType)System.ComponentModel.TypeDescriptor.CreateInstance(
        provider: null, // use standard type description provider, which uses reflection
        objectType: objectType,
        argTypes: new Type[] { types, of, args },
        args: new object[] { args, to, constructor }
    );



public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}



Related