【问题标题】:How can I specify default values for method parameters in c#7 tuples?如何为 c#7 元组中的方法参数指定默认值?
【发布时间】:2017-06-13 00:51:22
【问题描述】:

在 C# 中,您可以定义默认参数,如 here 所述。我正在玩元组和 C#7(使用 LinqPad 并打开 Preferences -> Queries -> Use Roslyn assemblies)如下:

void Main()
{   
    var result=AddTuples((1, 2),  (3, 4));
    Console.WriteLine($"Result is: {result}");
}

(int x, int y) AddTuples((int x, int y) a,  (int x, int y) b)
{
    return (a.x + b.x,  a.y + b.y);
}

这很好用,它显示了 a 和 b 的总和:

结果是:(4, 6)

现在我试图将AddTuples 修改为具有默认参数,但不知何故我无法弄清楚如何。我尝试的是这样的:

(int x, int y) AddTuples2((int x, int y) a = (0, 0),  (int x, int y) b = (0, 0))
{
    return (a.x + b.x,  a.y + b.y);
}

但我收到错误消息:

CS1736 'a' 的默认参数值必须是编译时常量

CS1736 'b' 的默认参数值必须是编译时常量

(在线试用DotNetFiddle

我做错了什么?


更新

感谢您提供的出色答案,我学到了很多东西。让我总结一下:要为元组参数设置默认值,有 3 个可能的选项:

  1. 老式方法:重载方法,在方法体中提供默认值。缺点:如果你有超过 2 个元组,重载就会变得很麻烦。
  2. Use nullable tuples,在方法体中提供默认值。
  3. Use tuple's default values
  4. Use a params array 允许方法参数中的元组超过 2 个,在方法体中提供默认值

注意:选项 1.、2. 和 4. 允许指定任何所需的默认值,而选项 3. 仅限于 default 关键字提供的默认值。

【问题讨论】:

  • 我想您将无法做到这一点,因为结构实例不能是常量,而元组实际上只是结构。
  • 创建另一个不带参数的方法,并从内部使用零元组调用您的方法
  • @Jan - 是的,我知道这总是可能的。我认为 C#7 的设计者实现了更多的语法糖......
  • 元组实际上只是一种编译器接受特殊初始化语法的结构,例如(int x, int y) a = (0,0),并且结构通常不是编译时常量,因为没有什么禁止结构具有产生任意副作用的构造函数,这反过来又与编译时常量相矛盾约束。要实现所需的行为,您需要对该方法进行多次重载。
  • @Matt 确实更优雅,但它是以拳击为代价的,如下所述:msdn.microsoft.com/en-us/library/ms228597.aspx。我想这只是偏好问题。在这种特殊情况下,我个人更喜欢性能而不是优雅。

标签: c# .net parameters default c#-7.0


【解决方案1】:

ab 不是常量。创建新实例的所有内容(无论是结构还是类)都不会被视为常量,方法签名只允许将常量作为默认值。

也就是说,没有办法从方法签名中默认元组,你必须创建一个单独的方法。

唯一的出路似乎是使用可为空的参数:

(int x, int y) AddTuples2((int x, int y)? a = null, (int x, int y)? b = null)
{
    (int x, int y) aNN = a ?? (0,0);
    (int x, int y) bNN = b ?? (0,0);
    return (aNN.x + bNN.x, aNN.y + bNN.y);
}

【讨论】:

  • 很好的解决方案,帕特里克! 注意:不需要引入新的局部变量,ab可以像函数体中的a = a ?? (0, 0);一样被覆盖。
  • 是的,但是你必须这样做a.Value.x
  • 你是对的,在这种情况下return (a.Value.x + b.Value.x, a.Value.y + b.Value.y); 是必需的——但它有效,而且我相信它看起来更具可读性! :-)
【解决方案2】:

只要您对 int 组件的默认初始化为零感到满意,您就可以指定默认值:

public static (int x, int y) AddTuples(
    (int x, int y) a = default((int, int)), 
    (int x, int y) b = default((int, int)))
{
    return (a.x + b.x, a.y + b.y);
}

很遗憾,您无法为元组的组件提供特定的默认值。

但是,对于您的具体示例(您希望默认为 (0, 0)),这似乎就足够了。


[附录]

此特定示例的另一种方法是使用params 数组:

public static (int x, int y) AddTuples(params (int x, int y)[] tuples)
{
    return (tuples.Sum(t => t.x), tuples.Sum(t => t.y));
}

然后你可以这样做:

Console.WriteLine($"Result is: {AddTuples()}");                       // (0, 0)
Console.WriteLine($"Result is: {AddTuples((1, 1))}");                 // (1, 1)
Console.WriteLine($"Result is: {AddTuples((1, 1), (2, 2))}");         // (3, 3)
Console.WriteLine($"Result is: {AddTuples((1, 1), (2, 2), (3, 3))}"); // (6, 6)

【讨论】:

  • 这类似于Patricks solution,但他实际上通过检查null并分配所需的默认值来解决它。
  • @Matt 实际上,他必须将参数类型从(int, int) 更改为(int, int)?,所以它有些不同。这种方法根本不会改变参数类型(但仅限于默认为默认值,因此不够灵活)。
  • 不错的一个。我不知道你可以为元组传递默认值
  • 很高兴知道这也有效,如果您只需要 (0, 0) 作为默认值就可以了。我给了你一票!
  • @SergeyBerezovskiy 从 C# 7 开始,这些元组是结构,因此您可以这样定义它们。
【解决方案3】:

VisualStudio 2017 建议对 Patricks 的回答进行以下简化:

(int x, int y) AddTuples2((int x, int y)? a = null, (int u, int v)? b = null)
{
    (int x, int y) = a ?? (0,0);
    (int u, int v) = b ?? (0,0);
    return (x + u, y + v);
}

【讨论】:

  • 好提示,这样看起来更简单,无需指定aNNbNN - 而是在参数中引入变量xyuv - 然后就使用它们。
猜你喜欢
  • 2011-12-06
  • 2011-03-24
  • 2012-12-16
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
  • 2020-04-07
相关资源
最近更新 更多