2011-06-12 66 views
3

我有一個結構這需要在給構造3個命名參數...通行證命名參數有條件

public struct MyData 
{ 
    private readonly double _value1; 
    private readonly double _value2; 
    private readonly double _value3; 

    public MyData(
     double value1 = 1.0, 
     double value2 = 2.0, 
     double value3 = 3.0) 
    { 
     _value1 = value1; 
     _value2 = value2; 
     _value3 = value3; 
    } 
} 

創建的類中,我想用它來創建三個雙打可空接收方法調用MyData類只有當可爲空的雙精度不爲空時...

public MyData CreateMyData(double? value1, double? value2, double? value3) 
{ 
    MyData myData; 
    if (value1.HasValue) 
    { 
     if (value2.HasValue) 
     { 
      if (value3.HasValue) 
      { 
       myData = new MyData(value1, value2, value3); 
      } 
      else 
      { 
       myData = new MyData(value1, value2); 
      } 
     } 
     else 
     { 
      if (value3.HasValue) 
      { 
       myData = new MyData(value1, value3: value3); 
      } 
      else 
      { 
       myData = new MyData(value1); 
      } 
     } 
    } 
    else 
    { 
     if (value2.HasValue) 
     { 
      if (value3.HasValue) 
      { 
       myData = new MyData(value2: value2, value3: value3); 
      } 
      else 
      { 
       myData = new MyData(value2: value2); 
      } 
     } 
     else 
     { 
      if (value3.HasValue) 
      { 
       myData = new MyData(value3: value3); 
      } 
      else 
      { 
       myData = new MyData(); 
      } 
     } 
    } 
    return myData; 
} 

是否有更好的方法來編寫此方法而不修改MyData類?即我可以有條件地傳遞命名參數,還是可以傳遞指示符來表示默認的命名參數值?

+2

爲什麼你不想修改'MyData'? – svick 2011-06-12 14:50:43

+0

在大多數情況下,我只是想知道是否有辦法在不修改MyData的情況下執行此操作。我問這是爲了防止MyData不受我控制(例如第三方庫或其他)的情況。至少現在至少有 – Noob 2011-06-12 16:00:40

+0

,大多數.Net庫不使用可選參數。 – svick 2011-06-12 16:15:36

回答

2
public MyData(
    double? value1 = null, 
    double? value2 = null, 
    double? value3 = null) 
{ 
    _value1 = value1 ?? 1.0; 
    _value2 = value2 ?? 2.0; 
    _value3 = value3 ?? 3.0; 
} 

這樣,您就可以直接通過null S和將不會從combinatorial explosion受到影響。此外,如果您決定更改默認值,即使沒有重新編譯此代碼的所有用戶,它也可以工作。

+1

他要求的解決方案不涉及修改'MyData' – InBetween 2011-06-12 14:44:06

+0

@InBetween,啊,我沒注意到。 – svick 2011-06-12 14:50:58

+0

這是一個非常有趣的答案。如果我正在爲第三方使用創建類,那麼在使用命名值類型參數時,這會是一種更好的設計類的更好方法嗎? – Noob 2011-06-12 16:04:32

0

也許你只想:

return new MyData(value1 ?? 1.0, value2 ?? 2.0, value3 ?? 3.0); 

+0

這種方式涉及具有控制默認值的調用方法。我希望默認的職責與MyData類共存。這意味着可以修改MyData類中的默認值,而不必查找對MyData類的所有引用。謝謝你的建議,但:-) – Noob 2011-06-12 14:26:38

+0

那麼,你可以讓'CreateMyData'成爲'MyData'的靜態方法(如果你被允許修改類)。 – Vlad 2011-06-12 14:28:29

+2

@noob:這個道理沒有道理。可選參數和默認參數在呼叫站點不在被叫方處解析。如果您更改默認參數,但不重新使用MyData重新編譯使用者代碼,則使用者代碼仍將以原始默認值調用,而不是新的。 – InBetween 2011-06-12 14:33:23

0
var t = typeof (MyData); 
var c = t.GetConstructor(new Type[] { typeof(double), typeof(double), typeof(double)}); 
var p = c.GetParameters(); 
return new MyData(value1 ?? p[0].DefaultValue, value2 ?? p[1].DefaultValue, value3 ?? p[2].DefaultValue); 
+0

是的,這看起來像是修改MyData類或硬編碼調用類中的默認值的唯一選擇。 – Noob 2011-06-12 15:49:14

1

檢查這個

public MyData CreateMyData(double? value1, double? value2, double? value3) 
    { 
     var ss= typeof(MyData).GetConstructor(new Type[]{typeof(double),typeof(double),typeof(double)}); 
     var parametesr = ss.GetParameters(); 
     return new MyData(value1 ?? Convert.ToDouble(parametesr[0].DefaultValue), value2 ?? Convert.ToDouble(parametesr[1].DefaultValue), value3 ?? Convert.ToDouble(parametesr[2].DefaultValue)); 
    } 
0

您需要後期綁定來做到這一點。開源框架ImpromptuInterface可讓您訪問dynamically pick named arguments所需的DLR功能。

using ImpromptuInterface; 

... 

public MyData CreateMyData(double? value1, double? value2, double? value3) 
{ 
    var arg = InvokeArg.Create; 
    var argList = new List<Object>(); 
    if(value1.HasValue) 
     argList.Add(arg("value1",value1)); 
    if(value2.HasValue) 
     argList.Add(arg("value2",value2)); 
    if(value3.HasValue) 
     argList.Add(arg("value3",value3)); 

    return Impromptu.InvokeConstructor(typeof(MyData), argList.ToArray()); 
}