2011-04-07 53 views
9

我使用Type.GetConstructor(Type.EmptyTypes)來獲取類的默認構造函數。如果該類具有不帶參數的默認構造函數(class A),它將起作用。但是,如果一個類具有一個構造函數,並且所有參數都是可選的(class B),則它不起作用。程序不知道可選參數是什麼,因爲它只需要默認的構造函數。我可以使用哪些語句使其適用於這兩種情況?謝謝,感謝任何幫助!如何在參數可選時獲取默認構造函數

public class A 
{ 
    public A() {} 
} 

public class B 
{ 
    public B(int i = 0, string str = "") {} 
} 
+0

感謝所有的答覆,他們非常豐富。由於這些是自動生成的類,我只是將其更改爲始終包含不帶參數的構造函數。 – dlsou 2011-04-08 12:14:15

+0

另請注意,如果'T'具有約束條件'where T:new()',那麼類'B'不能用於泛型類型參數'T'。公共實例構造函數不被視爲無參數,因爲它的所有參數都是可選的。 – 2014-02-27 08:01:37

回答

5

說我有下面的類:

public class SomeClass 
{ 
    public SomeClass() 
    { 

    } 

    public SomeClass(int x) 
    { 
    } 

    public SomeClass(int x = 0, int y = 0) 
    { 

    } 
} 

基本上,你要求的查詢會發現與上面的構造函數1和3匹配的構造函數?如果是這樣,使用此:

var constuctors = typeof(SomeClass).GetConstructors() 
      .Where(x => x.GetParameters().Count() == 0 
        || x.GetParameters().Count(param => param.GetCustomAttributes(typeof(OptionalAttribute), false).Count() > 0) == x.GetParameters().Count());  

令人難以置信的是討厭的查詢,但它會返回只有1和3以上完成任務。

+1

查看Damiens的答案,效率稍高。儘管如此,+1的想法 – nawfal 2013-04-24 04:34:44

3

問題是可選參數只不過是編譯時間的概念。你需要完全指定構造函數。

var ci = typeof(B).GetConstructor(new [] { typeof(int), typeof(string) }); 

您可以編寫一個幫助函數,它將調用具有默認值的構造函數。我的例子並不像應該那樣健壯,但它應該讓你開始。

static Func<T> CreateDefaultConstructor<T>(ConstructorInfo ci) 
{ 
    var l = new List<object>(); 
    foreach (var p in ci.GetParameters()) 
    { 
     if (p.IsOptional) 
     { 
      l.Add(p.RawDefaultValue); 
     } 
    } 
    return() => (T)ci.Invoke(l.ToArray()); 
} 
2

問題是,在B的情況下,它沒有沒有參數的構造函數。

可選參數是一個編譯時構造 - 在IL中,它是一個帶有2個參數(用屬性標記)的構造函數。因此,就Reflection而言,沒有默認的構造函數。

3

的問題是,C#編譯器生成的:

public class B 
{ 
    // Methods 
    public B([Optional, DefaultParameterValue(0)] int i, [Optional, DefaultParameterValue("")] string str) 
    { 
    } 
} 

類似下面應該工作:

public static class TypeHelper { 
    public static ConstructorInfo GetDefaultConstructor<TType>() { 
     var type = typeof(TType); 
     return type.GetDefaultConstructor(); 
    } 

    public static ConstructorInfo GetDefaultConstructor(this Type type) { 
     if(type == null) throw new ArgumentNullException("type"); 
     var constructor = type.GetConstructor(Type.EmptyTypes); 
     if(constructor == null) { 
      var ctors = 
       from ctor in type.GetConstructors() 
       let prms = ctor.GetParameters() 
       where prms.All(p=>p.IsOptional) 
       orderby prms.Length 
       select ctor;       
      constructor = ctors.FirstOrDefault(); 
     } 
     return constructor; 
    } 
} 
+1

您可以編寫一個LINQ語句來查找指定了可選和DefaultParameterValue的所有構造函數參數。 – Damian 2011-04-07 19:09:28

+0

或者只是可選;他們可能從來沒有用過自己。 – 2011-04-07 19:12:20

+0

很好的答案,但首選或缺省的方法並不合適。您決定爲用戶而不是C#重載運算符。我的意思是可能會出現編譯器對重載解析模糊不清的情況,但在這裏你正在爲他決定一個:) – nawfal 2013-04-24 04:42:51

0

當一個構造函數,或任何其他方法,具有可選參數,它不導致編譯器生成該方法的多個版本。相反,它會生成一個包含所有指定參數的方法。默認值在附加到方法簽名的屬性中進行編碼。這些用於呼叫站點以使其值可選。

所以這裏沒有默認的構造函數,而是一個一個有兩個參數的