ChatGPT解决这个技术问题 Extra ChatGPT

.NET 的未来版本会支持 C# 中的元组吗?

.Net 3.5 不支持元组。太糟糕了,但不确定.net 的未来版本是否支持元组?


A
Andreas Grech

我刚刚阅读了 MSDN 杂志上的这篇文章:Building Tuple

以下是节选:

即将发布的 Microsoft .NET Framework 4.0 版本引入了一种称为 System.Tuple 的新类型。 System.Tuple 是一个固定大小的异构类型数据集合。

像数组一样,元组具有固定的大小,一旦创建就无法更改。与数组不同,元组中的每个元素可能是不同的类型,并且元组能够保证每个元素的强类型。

在 System.Collections.Generic 命名空间中已经有一个在 Microsoft .NET Framework 中浮动的元组示例:KeyValuePair。虽然 KeyValuePair 可以被认为与 Tuple 相同,因为它们都是包含两个东西的类型,但 KeyValuePair 感觉与 Tuple 不同,因为它唤起了它存储的两个值之间的关系(并且有充分的理由,因为它支持 Dictionary 类)。此外,元组可以任意大小,而 KeyValuePair 只包含两个东西:一个键和一个值。

虽然 F# 等某些语言对元组有特殊语法,但您可以使用任何语言的新通用元组类型。回顾第一个例子,我们可以看到虽然有用,但元组在没有元组语法的语言中可能过于冗长:

class Program {
    static void Main(string[] args) {
        Tuple<string, int> t = new Tuple<string, int>("Hello", 4);
        PrintStringAndInt(t.Item1, t.Item2);
    }
    static void PrintStringAndInt(string s, int i) {
        Console.WriteLine("{0} {1}", s, i);
    }
}

使用 C# 3.0 中的 var 关键字,我们可以删除元组变量上的类型签名,从而使代码更具可读性。

var t = new Tuple<string, int>("Hello", 4);

我们还在静态 Tuple 类中添加了一些工厂方法,这使得使用支持类型推断的语言(如 C#)更容易构建元组。

var t = Tuple.Create("Hello", 4);

B
Benjol
#region tuples

    public class Tuple<T>
    {
        public Tuple(T first)
        {
            First = first;
        }

        public T First { get; set; }
    }

    public class Tuple<T, T2> : Tuple<T>
    {
        public Tuple(T first, T2 second)
            : base(first)
        {
            Second = second;
        }

        public T2 Second { get; set; }
    }

    public class Tuple<T, T2, T3> : Tuple<T, T2>
    {
        public Tuple(T first, T2 second, T3 third)
            : base(first, second)
        {
            Third = third;
        }

        public T3 Third { get; set; }
    }

    public class Tuple<T, T2, T3, T4> : Tuple<T, T2, T3>
    {
        public Tuple(T first, T2 second, T3 third, T4 fourth)
            : base(first, second, third)
        {
            Fourth = fourth;
        }

        public T4 Fourth { get; set; }
    }

    #endregion

并使声明更漂亮:

public static class Tuple
{
    //Allows Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2")
    public static Tuple<T1, T2> New<T1, T2>(T1 t1, T2 t2)
    {
        return new Tuple<T1, T2>(t1, t2);
    }
    //etc...
}

虽然问题在于 MS 在 .NET 4 中提供它,但这是目前管理它的好方法。 +1
如果您不需要比较两个元组的相等性,这种继承方法很好。我想在我的实现中实现 IEquatable> 等等,所以我不能使用继承,因为我不希望 Tuple 等于 Tuple
@Joel,您可以让 Equals 检查两个参数的动态类型。
您将如何在代码中使用它? t = 新元组 (1, 2); t.First 和 t.Second?
我看到您使用继承 - 您真的希望能够将 Tuple<T1,T2,T3> 作为 Tuple<T1,T2> 传递吗?答案很可能是否定的。
R
Rinat Abdullin

Lokad Shared Libraries(当然是开源的)中有一个适当的(不快)C# Tuple 实现,其中包括以下必需功能:

2-5 不可变元组实现

正确的 DebuggerDisplayAttribute

正确的散列和相等检查

用于从提供的参数生成元组的助手(泛型由编译器推断)和基于集合的操作的扩展。

生产测试。


C
Chris Ballard

在 C# 中实现元组类或重用 F# 类只是故事的一半——这些使您能够相对轻松地创建元组,但并不是真正的语法糖,使它们在 F# 等语言中使用起来非常好。

例如,在 F# 中,您可以使用模式匹配在 let 语句中提取元组的两个部分,例如

let (a, b) = someTupleFunc

不幸的是,使用 C# 中的 F# 类做同样的事情会不太优雅:

Tuple<int,int> x = someTupleFunc();
int a = x.get_Item1();
int b = x.get_Item2();

元组代表了一种强大的方法,可以从函数调用中返回多个值,而无需在代码中乱扔垃圾类,或者使用丑陋的 ref 或 out 参数。然而,在我看来,如果没有一些语法糖来使它们的创建和访问更加优雅,它们的用途是有限的。


那么匿名类型呢?
这允许您将 Tuple 替换为 var,但您仍然会得到三行代码而不是一行
也许这就是我们将在 C# 4.0 中看到的东西。语法糖如 int a, b = someTupleFunc();在编译器级别应该是完全可行的。
A
Andreas Grech

在我看来,匿名类型特性不是一个元组,而是一个非常相似的构造。一些 LINQ 查询的输出是匿名类型的集合,其行为类似于元组。

这是一个语句,它动态创建一个类型化的元组:-):

var p1 = new {a = "A", b = 3};

见:http://www.developer.com/net/csharp/article.php/3589916


L
LW001

C# 7 原生支持元组:

var unnamedTuple = ("Peter", 29);
var namedTuple = (Name: "Peter", Age: 29);
(string Name, double Age) typedTuple = ("Peter", 29);

.NET 4.7 开始,这是开箱即用的,因为旧版本的 .NET 不包含所需的 ValueTuple 结构。但是,您可以提供这些,例如通过像 ValueTupleBridge 这样的 NuGet 包。
MS 现在有一个用于所需元组类的官方 nuget 包
n
naasking

我的开源 .NET Sasa library 多年来一直拥有元组(以及许多其他功能,例如完整的 MIME 解析)。几年来,我一直在生产代码中使用它。


M
Matt Davis

C# 很容易通过泛型支持简单的元组(根据较早的答案),并且通过“mumble typing”(许多可能的 C# 语言增强之一)来改进类型推断,它们可能非常非常强大。

对于它的价值,F# 本身就支持元组,并且在使用它之后,我不确定(匿名)元组增加了多少......你获得的简洁性很快就会失去代码清晰度。

对于单个方法中的代码,有匿名类型;对于方法之外的代码,我想我会坚持使用简单的命名类型。当然,如果未来的 C# 可以更容易地使这些不可变(同时仍然易于使用),我会很高兴。


好处之一是对于 TryParse 之类的东西,您可以在其中编写 'valid value = double.TryParse("1.02")' 并分配多个返回值,而无需任何笨拙的输出参数。但总的来说,我同意纯粹的位置数据结构并不是一件好事。
同意 - 多个返回值是元组的最佳用例,除此之外,代码中的元组几乎没有什么用途。尽管在允许元组的情况下,这应该是一个约定而不是限制。如果 .NET 语言提供了一种将返回对象“分解”为多个值而不是引入元组数据类型的方法,我认为会更简洁。像 { j = ErrorCode, h = ResultObj } = SomeFunction()(其中 jh 是本地变量)这样的东西会比元组更有帮助。
L
Lasse V. Karlsen

这是我的一组元组,它们是由 Python 脚本自动生成的,所以我可能有点过火了:

Link to Subversion repository

你需要一个用户名/密码,他们都是客人

它们基于继承,但 Tuple<Int32,String> 不会与 Tuple<Int32,String,Boolean> 比较,即使它们碰巧对前两个成员具有相同的值。

他们还实现了 GetHashCode 和 ToString 等,以及许多小的辅助方法。

使用示例:

Tuple<Int32, String> t1 = new Tuple<Int32, String>(10, "a");
Tuple<Int32, String, Boolean> t2 = new Tuple<Int32, String, Boolean>(10, "a", true);
if (t1.Equals(t2))
    Console.Out.WriteLine(t1 + " == " + t2);
else
    Console.Out.WriteLine(t1 + " != " + t2);

将输出:

10, a != 10, a, True

但这还不是全部。如果它基于继承,我想你可以写 Tuple<Int32, String> t1 = new Tuple<Int32, String, Boolean>(10, "a", true); 等。我不确定是否有任何需要的场景。
T
Tigraine

如果我没记错我的计算机科学课,元组只是数据。

如果您想要分组数据 - 创建包含属性的类。如果您需要类似 KeyValuePair 的东西,那么它就在那里。


就像 if 语句只是带有语句块的 goto 一样。如果您习惯了元组,那么元组很好,并且在特定情况下,类似乎不必要且笨拙...
除非您需要从函数中返回 5 个项目,否则就是这样。当然,您可以创建自己的泛型类,但 C# 7 中的语法更加简洁明了。
M
Merus

我会感到惊讶 - C# 是一种强类型语言,而元组适用于更动态类型的语言。随着时间的推移,C# 变得更加动态,但这是语法糖,而不是底层数据类型的真正转变。

如果您想在一个实例中使用两个值,则 KeyValuePair<> 是一个不错的替代品,尽管很笨拙。您还可以创建一个结构或类来做同样的事情,并且是可扩展的。


“C# 变得更加动态” - 不,它一直在变得更加隐含/推断;它仍然是一种完全静态的语言。但是,更好的动态支持(用于使用 DLR 类)很可能是未来的语言增强。
您如何解释元组在 F#、Haskell 或任何其他完全支持它们的强类型和静态类型语言中的存在......?
佚名

为了使这些在哈希表或字典中有用,您可能希望为 GetHashCode 和 Equals 提供重载。