【问题标题】:Any reason tu use out parameters with the C# 7 tuple return values? [closed]你有什么理由使用带有 C# 7 元组返回值的参数? [关闭]
【发布时间】:2016-12-12 21:25:10
【问题描述】:

我刚刚观看了介绍new features of C# 7 的视频。其中,它引入了返回元组类型的可能性(例如:(int, int),我相信这只是Tuple<int, int> 的语法糖)。因此,如果我们有一个返回多个值的方法,那么 C# 中有 3 种可能性:

(int first, int second) ReturnTuple()
{
    return (1, 2);
}

int ReturnOutParam(out int second)
{
    second = 2;
    return 1;
}

CustomObject ReturnObject()
{
    return new CustomObject
    {
        First = 1,
        Second = 2
    };
}

我相信,没有其他方法可以做到这一点 - 如果是,请纠正我。

这三种方法中哪一种是正确的?在哪些情况下我们可以使用剩下的两个?对于每一个新的 C# 版本,我都有一种感觉,在 .NET 世界中,有一两种设计模式已经过时了。一些特性非常有用(如泛型、部分、LINQ、lambdas、async/await 或 null 传播器)。其他的则非常情境化(动态,nameof)。还有一些对我来说没有意义的东西(属性自动初始化器、元组返回值或本地函数)。

【问题讨论】:

  • “这三种方法中哪一种是正确的?” 好吧,它们都有效,所以从这个意义上说,它们都是“正确的”。哪一个实际上适合特定场景将取决于场景。话虽如此,第二个似乎真的很尴尬。
  • 您可以就正常参数提出同样的问题。为什么将方法声明为f(int a, int b, int c) 而不是f(Tuple<int, int, int> abc)f(CustomClass abc)?如果这些值是按逻辑分组的(例如,如果更频繁地使用它们,您会考虑将它们创建一个类),然后使用元组。如果没有,请将它们分开。
  • 您展示的第 3 种方法强制您定义一个只需要返回 2 个值的类(并且可能在程序中的其他任何地方都没有使用它)。输出参数....我一直不喜欢它们(无法告诉你为什么...)返回多个值的语言支持对我来说似乎是件好事。当然,如果你愿意,你可以用旧的方式做同样的事情

标签: c# c#-7.0


【解决方案1】:

首先,像(int, int) 这样的元组是ValueTuple<int, int> 的语法糖。 TupleValueTuple的区别是:

  • ValueTuple 是值类型,所以不需要在堆上分配对象
  • ValueTuple 是可变的
  • ValueTuple 具有(显然)内置语言支持,它允许您通过自定义属性(TupleElementNamesAttribute)命名元组项。使用Tuple,您只会得到Item1Item2 等。

随着每个新的语言版本,一些功能变得过时。例如,delegate { } 语法被 lambdas 取代。您可能会争辩说out 参数属于此类别,但这是主观的。然而,所有功能都需要保留在那里以实现向后兼容性。

例如,bool int.TryParse(string input, out int value) 应该变成 int? int.TryParse(string input) 并在语言中包含可空值类型,但旧函数已经存在于框架中,所以它必须保留。

我的经验法则是:对私有方法或实用函数使用值元组,但更喜欢对任何公共 API 使用成熟的结构,这样感觉更干净。我通常避免使用 out 参数,除非偶尔用于私有方法。

我不明白为什么其中一些新功能对您没有意义:

  • 属性自动初始化器终于在那里,它们应该首先与自动属性一起实现,但可能由于时间限制而被跳过。这对代码的可读性来说是一个明显的胜利,它增加了一个字段始终存在的功能。
  • 元组返回值是您问题的主题,这也是对旧元组的明显可读性胜利。能够命名您的元组项目本身就说明了问题。
  • 本地函数在实现迭代器模式时最有用,但我偶尔希望拥有这样的功能并通过使用 lambda 来解决它。

【讨论】:

    【解决方案2】:

    对我来说,这仍然取决于情况。例如对于TryParse,它仍然更具可读性:

    if (int.TryParse("123", out var i))
    {
       // i
    }
    

    var (success, i) = int.TryParse("123");
    if (success)
    {
       // i
    }
    

    在大多数情况下,从方法返回多个值是一种代码异味。您应该始终将返回的内容包装到比FirstSecond 更好地描述您的值的类中。

    【讨论】:

    • 值得记住的是,如果 int.TryParse 返回一个元组,你可以这样做 if (int.TryParse("123") is var (success, i) && success) { // use i here...
    • 只是缺少正常的模式匹配。看看 Rust,它对此类结构的处理非常好
    • 使用 out var i 有点好,我不知道会起作用
    猜你喜欢
    • 2011-10-12
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-10
    • 1970-01-01
    相关资源
    最近更新 更多