【问题标题】:Pass Named Parameter Conditionally有条件地传递命名参数
【发布时间】:2011-09-13 10:10:43
【问题描述】:

我有一个结构,它在构造函数中接受 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 类? IE。 我可以有条件地传递命名参数还是传递一个指标来表示默认的命名参数值?

【问题讨论】:

  • 为什么不想修改MyData
  • 在大多数情况下我都会这样做,我只是想知道是否有一种方法可以在不修改 MyData 的情况下做到这一点。我问这个以防万一我遇到 MyData 不受我控制的情况(例如 3rd 方库或其他东西)。
  • 至少目前,大多数 .Net 库不使用可选参数。
  • 仅供参考,在您的示例中,因为 MyData 是 struct 而不是 class,请务必注意 CreateMyData2(null,null,null) 将返回 MyData 与 _value1,_value2,_value3 相等为零。无论如何,结构都有默认构造函数,并且将优先于可选参数构造函数。

标签: c# c#-4.0 named-parameters


【解决方案1】:

您需要后期绑定才能做到这一点。开源框架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());
}

【讨论】:

    【解决方案2】:

    检查一下

       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)); 
        }
    

    【讨论】:

      【解决方案3】:
      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);
      

      【讨论】:

      • 是的,这看起来像是修改 MyData 类或硬编码调用类中的默认值的唯一替代方法。
      【解决方案4】:
      public MyData(
          double? value1 = null,
          double? value2 = null,
          double? value3 = null)
      {
          _value1 = value1 ?? 1.0;
          _value2 = value2 ?? 2.0;
          _value3 = value3 ?? 3.0;
      }
      

      这样,您可以直接传递nulls,而不会受到combinatorial explosion的影响。

      此外,如果您决定更改默认值,即使不重新编译此代码的所有用户,它也可以工作。

      【讨论】:

      • 他要求的解决方案不涉及修改MyData
      • @InBetween,啊,我没注意到。
      • 这是一个非常有趣的答案。如果我正在为第 3 方创建类,那么在使用命名值类型参数时,这是否是设计类的更好方法?
      • @Noob,如果您将来可以更改默认值,那么绝对可以。如果不是这样,那么是的,可能。
      【解决方案5】:

      也许你只想要:

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

      ?

      【讨论】:

      • 这种方式涉及控制默认值的调用方法。我希望默认值的责任与 MyData 类一起使用。这意味着可以修改 MyData 类中的默认值,而无需查找对 MyData 类的所有引用。不过感谢您的建议:-)
      • 好吧,你可以将CreateMyData 设为MyData 的静态方法(如果允许修改类的话)。
      • @noob:这个理由没有意义。可选参数和默认参数在调用站点而不是被调用者处解析。如果您更改默认参数但不重新编译消费者代码和MyData,消费者代码仍将使用原始默认值调用,而不是新默认值。
      • 对,知道这很有趣。即使我仍然必须重新编译所有引用,在 MyData 类中定义它们仍然很好。非常感谢你告诉我这件事,这是我以前不知道的。
      猜你喜欢
      • 1970-01-01
      • 2011-06-07
      • 1970-01-01
      • 2013-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-13
      • 1970-01-01
      相关资源
      最近更新 更多