2011-05-30 46 views
3

我們知道你可以指向一個構造函數爲Func<T>這樣的:C#:FUNC具有遺傳型的構造

Func<MyObject> constructor =() => new MyObject(); 
var newObject = constructor(); 

但是,有沒有辦法讓你知道一個對象的構造繼承自MyObject,但是你不知道它的確切類型?

Type inheritedObjectType = obj; // Parameter 
Func<MyObject> constructor =() => new MyObject(); // as inheritedObjectType 
var newInheritedObject = constructor; // Should now be of the inherited type 

的答案用Activator或任何返回Object是不是一種選擇。

編輯:我不知道在編譯時派生類型是什麼類型。我只有一個System.Type

回答

7

您可以使用表達式樹構建和編譯的委託,將創建您的派生類型:

Func<TBase> CreateDelegate<TBase>(Type derived) 
{ 
    var ctor = derived.GetConstructor(Type.EmptyTypes); 

    if (ctor == null) 
    { 
     throw new ArgumentException("D'oh! No default ctor."); 
    } 

    var newExpression = Expression.Lambda<Func<TBase>>(
     Expression.New(ctor, new Expression[0]), 
     new ParameterExpression[0]); 

    return newExpression.Compile(); 
} 

你可以簡單地調用它,如下所示:當您緩存該委託

Func<MyBase> create = CreateDelegate<MyBase>(typeof(Derived)); 

MyBase instance = create(); 

,你將獲得最高的性能。

+1

btw:到底什麼依賴注入框架會爲你做。大多數框架將允許註冊一個語法如下:'container.Register(typeof(MyBase),derived)',你可以得到一個新的實例,如下所示:'container.GetInstance ()'et瞧。 – Steven 2011-05-30 14:37:00

+0

它工作完美。 – 2011-05-30 14:39:18

2

此程序是否表現出所需的行爲?

class MyObject{} 
class Derived : MyObject {} 
internal class Program 
{ 

    public static void Main() 
    { 
     // the type you want to construct 
     Type type = typeof (Derived); 

     MethodInfo getConstructor = MakeConstructorGetter(type); 
     Func<MyObject> constructor = (Func<MyObject>)getConstructor.Invoke(null, null); 

     var obj = constructor(); 
     Console.WriteLine(obj.GetType()); 
    } 

    private static MethodInfo MakeConstructorGetter(Type type) 
    { 
     MethodInfo mi = typeof(Program).GetMethod("GetObjectConstructor", BindingFlags.Static | BindingFlags.NonPublic); 
     var getConstructor = mi.MakeGenericMethod(type); 
     return getConstructor; 
    } 

    private static Func<T> GetObjectConstructor<T>() where T : MyObject, new() 
    { 
     return() => new T(); 
    } 
} 

MakeConstructorGetter將拋出一個異常,如果由Type描述的類型不匹配的泛型約束。所以,這會在執行時間而不是在編譯期間失敗,但我想這是一個平衡,你需要做這樣動態處理泛型。

+0

我不知道「派生」是什麼,而不是一個System.Type。 – 2011-05-30 14:08:07

+0

@Seb:更新了答案,以便爲給定的'Type'構造一個通用方法。 – 2011-05-30 14:14:21

+0

嗯,「getConstructor.Invoke」基本上就像Activator.CreateInstance,並返回一個Object。我想引用構造函數lambda的性能,這是基於反射的等價物不太完美。如果無法完成,那麼這就是正確的答案,而解決方案是最接近的解決方案。 – 2011-05-30 14:18:16