2011-06-12 47 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()); 
}