有什么理由将 out 参数与 C# 7 元组 return 值一起使用?
Any reason tu use out parameters with the C# 7 tuple return values?
我刚刚观看了介绍 new features of C# 7 的视频。其中,它引入了 return 元组类型的可能性(例如:(int, int)
,我相信这只是 Tuple<int, int>
的语法糖)。因此,如果我们有一个方法 returning 多个值,在 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、lambda、async/await 或 null 传播器)。其他的是非常有情境的(动态的,nameof)。还有一些对我来说没有意义(属性 自动初始化器、元组 return 值或局部函数)。
对我来说还是要看情况。例如对于 TryParse
它仍然更具可读性:
if (int.TryParse("123", out var i))
{
// i
}
比
var (success, i) = int.TryParse("123");
if (success)
{
// i
}
并且在大多数情况下 return 从方法中获取多个值是一种代码味道。您应该始终将 return 包装到 class 中,这比 First
和 Second
.
更能描述您的价值观
首先,像 (int, int)
这样的元组是 ValueTuple<int, int>
的语法糖。 Tuple
和ValueTuple
的区别是:
ValueTuple
是值类型,所以不需要在堆上分配对象
ValueTuple
是可变的
ValueTuple
具有(显然)内置语言支持,它允许您通过自定义属性 (TupleElementNamesAttribute
) 命名元组项。使用 Tuple
,您只会得到 Item1
、Item2
等
对于每个新的语言版本,一些功能都已过时。例如,delegate { }
语法已被 lambda 表达式取代。您可能会争辩说 out
参数属于此类,但这是主观的。然而,所有功能都需要保留在那里以实现向后兼容性。
例如,bool int.TryParse(string input, out int value)
应该变成 int? int.TryParse(string input)
并在语言中包含可为 null 的值类型,但旧函数已经存在于框架中,因此它必须保留。
我的经验法则是:对私有方法或实用函数使用值元组,但对任何 public API 更喜欢完整的结构,这样感觉更干净。我通常避免使用 out
参数,但偶尔会使用私有方法。
我不明白为什么其中一些新功能对您没有意义:
- 属性 自动初始化 finally 在那里,它们应该首先与自动属性一起实现,但由于时间限制可能被跳过.这明显提高了代码的可读性,并且添加了字段始终存在的功能。
- 元组 return 值是您问题的主题,这也是对旧元组的明显可读性胜利。能够命名您的元组项不言自明。
- 局部函数将主要用于实现迭代器模式,但我偶尔希望拥有这样的功能并通过使用 lambda 解决它。
我刚刚观看了介绍 new features of C# 7 的视频。其中,它引入了 return 元组类型的可能性(例如:(int, int)
,我相信这只是 Tuple<int, int>
的语法糖)。因此,如果我们有一个方法 returning 多个值,在 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、lambda、async/await 或 null 传播器)。其他的是非常有情境的(动态的,nameof)。还有一些对我来说没有意义(属性 自动初始化器、元组 return 值或局部函数)。
对我来说还是要看情况。例如对于 TryParse
它仍然更具可读性:
if (int.TryParse("123", out var i))
{
// i
}
比
var (success, i) = int.TryParse("123");
if (success)
{
// i
}
并且在大多数情况下 return 从方法中获取多个值是一种代码味道。您应该始终将 return 包装到 class 中,这比 First
和 Second
.
首先,像 (int, int)
这样的元组是 ValueTuple<int, int>
的语法糖。 Tuple
和ValueTuple
的区别是:
ValueTuple
是值类型,所以不需要在堆上分配对象ValueTuple
是可变的ValueTuple
具有(显然)内置语言支持,它允许您通过自定义属性 (TupleElementNamesAttribute
) 命名元组项。使用Tuple
,您只会得到Item1
、Item2
等
对于每个新的语言版本,一些功能都已过时。例如,delegate { }
语法已被 lambda 表达式取代。您可能会争辩说 out
参数属于此类,但这是主观的。然而,所有功能都需要保留在那里以实现向后兼容性。
例如,bool int.TryParse(string input, out int value)
应该变成 int? int.TryParse(string input)
并在语言中包含可为 null 的值类型,但旧函数已经存在于框架中,因此它必须保留。
我的经验法则是:对私有方法或实用函数使用值元组,但对任何 public API 更喜欢完整的结构,这样感觉更干净。我通常避免使用 out
参数,但偶尔会使用私有方法。
我不明白为什么其中一些新功能对您没有意义:
- 属性 自动初始化 finally 在那里,它们应该首先与自动属性一起实现,但由于时间限制可能被跳过.这明显提高了代码的可读性,并且添加了字段始终存在的功能。
- 元组 return 值是您问题的主题,这也是对旧元组的明显可读性胜利。能够命名您的元组项不言自明。
- 局部函数将主要用于实现迭代器模式,但我偶尔希望拥有这样的功能并通过使用 lambda 解决它。