2009-12-05 121 views
123

在C#中,你可以把一個約束在一個通用的方法,如:在C#中有參數約束的泛型構造函數嗎?

public class A { 

    public static void Method<T> (T a) where T : new() { 
     //...do something... 
    } 

} 

如果您指定T應該有一個不需要參數的構造函數。我不知道是否有添加約束類似的方式

下面的代碼無法編譯「存在有float[,]參數的構造函數?」:

public class A { 

    public static void Method<T> (T a) where T : new(float[,] u) { 
     //...do something... 
    } 

} 

一種解決方法是也有用?

+0

的可能重複[如何約束通用類型必須有一個construtor這需要一定的參數?](http://stackoverflow.com/questions/853703/how-to-constrain-generic-type-to -must-have-a-construtor-that-c​​ertain-certain-param) – nawfal 2014-07-16 14:52:10

回答

115

正如您看到的,你不能做到這一點。

作爲一種變通方法,我通常提供一個委託,它可以創建T類型的對象:

public class A { 

    public static void Method<T> (T a, Func<float[,], T> creator) { 
     //...do something... 
    } 

} 
+37

是參數化的構造函數約束由於邏輯原因而缺失,還是僅僅是尚未被添加到語言中的東西? – 2011-08-23 03:34:12

+18

同意......我們應該有'new(float,double)','new(string)'等等 – SliverNinja 2012-02-01 17:47:15

+8

@Sahuagin我認爲這是不可能的,因爲當你從一個類繼承時,不能保證子類具有構造函數被定義,因爲構造函數沒有被繼承。然而,每個類都有一個空的參數構造函數。 – Matthew 2012-03-03 00:21:20

5

否。目前唯一可以指定的構造函數約束是針對無參數構造函數的。

39

沒有這樣的結構。您只能指定一個空的構造函數約束。

我用lambda方法解決了這個問題。

public static void Method<T>(Func<int,T> del) { 
    var t = del(42); 
} 

使用案例

Method(x => new Foo(x)); 
+0

沒有辦法在'Method'內抽象創建'Foo'? – 2015-11-13 15:52:24

+0

如果Method的用戶使用Method(x => new Foo());'?無論如何確保lambda應該是這樣嗎? – 2015-11-13 15:53:31

15

這是解決類似的問題,我個人覺得相當有效。如果你想到通用的參數化構造函數約束是什麼,它實際上是具有特定簽名的類型和構造函數之間的映射。您可以使用字典創建自己的這種映射。在一個靜態的「工廠」類把這些和你可以不必擔心每次建立一個構造函數拉姆達創建不同類型的對象:

public static class BaseTypeFactory 
{ 
    private delegate BaseType BaseTypeConstructor(int pParam1, int pParam2); 

    private static readonly Dictionary<Type, BaseTypeConstructor> 
    mTypeConstructors = new Dictionary<Type, BaseTypeConstructor> 
    { 
     { typeof(Object1), (pParam1, pParam2) => new Object1(pParam1, pParam2) }, 
     { typeof(Object2), (pParam1, pParam2) => new Object2(pParam1, pParam2) }, 
     { typeof(Object3), (pParam1, pParam2) => new Object3(pParam1, pParam2) } 
    }; 

然後在通用的方法,例如:

public static T BuildBaseType<T>(...) 
     where T : BaseType 
    { 
     ... 
     T myObject = (T)mTypeConstructors[typeof(T)](value1, value2); 
     ... 
     return myObject; 
    } 
+1

爲什麼這配得上拇指?根據我的經驗,它工作得很好。 – 2012-02-09 02:35:31

+1

我現在使用這個,我認爲這是一個很好的模式。工廠模式非常好。謝謝! – Matthew 2012-03-02 20:46:14

32

使用反射來創建通用對象,該類型仍需要聲明正確的構造函數或引發異常。只要符合其中一個構造函數,就可以傳入任何參數。

使用這種方式,您不能在模板中的構造函數上施加約束。 如果缺少構造函數,則需要在運行時處理異常,而不是在編譯時收到錯誤。

// public static object CreateInstance(Type type, params object[] args); 

// Example 1 
T t = (T)Activator.CreateInstance(typeof(T)); 
// Example 2 
T t = (T)Activator.CreateInstance(typeof(T), arg0, arg1, arg2, ...); 
// Example 3 
T t = (T)Activator.CreateInstance(typeof(T), (string)arg0, (int)arg1, (bool)arg2); 
相關問題