.NET Framework 3.5 的元组 (.NET 4) 等效项

Posted

技术标签:

【中文标题】.NET Framework 3.5 的元组 (.NET 4) 等效项【英文标题】:Equivalent of Tuple (.NET 4) for .NET Framework 3.5 【发布时间】:2011-08-19 11:24:29 【问题描述】:

.NET Framework 3.5 中是否存在与 .NET 4 Tuple 等效的类?

我想使用它来从一个方法返回多个值,而不是创建一个struct

【问题讨论】:

简答为否。 请看我对两个项目的Tuple 类的简单实现的回答。 我使用元组的次数越多,我就越喜欢专门的结构——当你不记得里面有什么时,.Item1、.Item2 的模棱两可有点烦人.. 为什么不返回一个带有你想要返回的公共成员的类的实例而不是一个结构呢?我认为这让一切都更加自我记录。和结构一样,但我个人更喜欢类而不是结构。 @Wardy KeyValuePair 暗示有一个 valuekey 相关联。不是我当时想要的。 【参考方案1】:

不,不在 .Net 3.5 中。但是创建自己的应该没有那么难。

public class Tuple<T1, T2>

    public T1 First  get; private set; 
    public T2 Second  get; private set; 
    internal Tuple(T1 first, T2 second)
    
        First = first;
        Second = second;
    


public static class Tuple

    public static Tuple<T1, T2> New<T1, T2>(T1 first, T2 second)
    
        var tuple = new Tuple<T1, T2>(first, second);
        return tuple;
    

更新:将静态内容移至静态类以进行类型推断。通过更新,您可以编写 var tuple = Tuple.New(5, "hello"); 之类的内容,它会为您隐式修复类型。

【讨论】:

它不必涉及更多,这取决于您的业务需求。问题是:“我想使用它来从一个方法返回多个值,而不是创建一个结构。”你不需要比较和平等。 一,你还没有提供 .NET 4.0 元组给你的 Equals 实现,二,你在谈论最后一种情况下的类型推断而不是隐式转换。 @nawfal,谢谢你关于类型推断。关于 equals 实现,您可能需要我的评论。根据业务需求,这可能不需要,我回答了具体问题,并没有编写完整的实现,因为它是在 .NET 4.0 中实现的。另外,我没有说这是一个完整的元组实现。 嗯。 q 大约相当于 .NET 4.0 元组。不要吹毛求疵,但元组的相等性是初学者通常会忽略的。这一点实际上值得一提。 仅供参考,Tuple 类似乎在 .NET 4.5 中发生了变化;这些属性称为Item1Item2,而不是FirstSecond【参考方案2】:

我在我的 pre-4 项目中使用它:

public class Tuple<T1>  
 
    public Tuple(T1 item1) 
     
        Item1 = item1; 
       

    public T1 Item1  get; set;   
 

public class Tuple<T1, T2> : Tuple<T1>  
 
    public Tuple(T1 item1, T2 item2) : base(item1) 
     
        Item2 = item2; 
     

    public T2 Item2  get; set;   
 

public class Tuple<T1, T2, T3> : Tuple<T1, T2>  
 
    public Tuple(T1 item1, T2 item2, T3 item3) : base(item1, item2) 
     
        Item3 = item3; 
     

    public T3 Item3  get; set;   
 

public static class Tuple  
 
    public static Tuple<T1> Create<T1>(T1 item1) 
     
        return new Tuple<T1>(item1); 
     

    public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) 
     
        return new Tuple<T1, T2>(item1, item2); 
     

    public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) 
     
        return new Tuple<T1, T2, T3>(item1, item2, item3); 
      

【讨论】:

为什么需要Tuple&lt;T1&gt;?这甚至是一个元组吗?【参考方案3】:

如果您需要它们与 .Net 4.0 具有相同的功能(主要是比较):

static class Tuple

    public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
    
        return new Tuple<T1, T2>(item1, item2);
    


[DebuggerDisplay("Item1=Item1;Item2=Item2")]
class Tuple<T1, T2> : IFormattable

    public T1 Item1  get; private set; 
    public T2 Item2  get; private set; 

    public Tuple(T1 item1, T2 item2)
    
        Item1 = item1;
        Item2 = item2;
    

    #region Optional - If you need to use in dictionaries or check equality
    private static readonly IEqualityComparer<T1> Item1Comparer = EqualityComparer<T1>.Default;
    private static readonly IEqualityComparer<T2> Item2Comparer = EqualityComparer<T2>.Default;

    public override int GetHashCode()
    
        var hc = 0;
        if (!object.ReferenceEquals(Item1, null))
            hc = Item1Comparer.GetHashCode(Item1);
        if (!object.ReferenceEquals(Item2, null))
            hc = (hc << 3) ^ Item2Comparer.GetHashCode(Item2);
        return hc;
    
    public override bool Equals(object obj)
    
        var other = obj as Tuple<T1, T2>;
        if (object.ReferenceEquals(other, null))
            return false;
        else
            return Item1Comparer.Equals(Item1, other.Item1) && Item2Comparer.Equals(Item2, other.Item2);
    
    #endregion

    #region Optional - If you need to do string-based formatting
    public override string ToString()  return ToString(null, CultureInfo.CurrentCulture); 
    public string ToString(string format, IFormatProvider formatProvider)
    
        return string.Format(formatProvider, format ?? "0,1", Item1, Item2);
    
    #endregion

【讨论】:

不错的答案。这就是我一直在寻找的(我在一个项目中,我被困在 3.5)。问题:您的GetHashCode() 实现是(h1 &lt;&lt; 3) ^ h2,而MS 1(经过ILSpy)是(h1 &lt;&lt; 5) + h1 ^ h2。它真的有影响吗(性能方面)? @tigrou XOR 应该就习惯使用它的硅数量而言稍微快一点(尽管它仍然是一条 CPU 指令)。不过,这严重过度微优化 - 随意使用您认为合适的任何一个。 我在考虑可能的冲突,而不是计算哈希码所花费的时间。 @tigrou 我想唯一的方法就是测试它。 这很好,避免了装箱(即使是 .NET 实现也不这样做)。一个小建议,你不需要在你的哈希码函数中检查空值,比较器会为你做。【参考方案4】:

您可以通过 nuget 安装 NetLegacySupport.Tuple。这是从 .Net 4.5 向后移植到 .Net 2.0 和 3.5 的 Tuple 类。

您可以通过 Visual Studio 中的包管理器或在命令行上使用 nuget 安装它。

这里是 nuget 包:

https://www.nuget.org/packages/NetLegacySupport.Tuple

【讨论】:

【参考方案5】:

是的,有一个名为 System.Collections.Generic.KeyValuePair 的类可以做同样的事情(我认为是从 .NET 2.0 开始)。

http://msdn.microsoft.com/en-us/library/5tbh8a42.aspx

【讨论】:

是的,但如果你想返回两个以上的值,那它就没有多大用处了。尽管您可以将 KeyValuePairs 嵌套在其他 KeyValuePairs 中以进行快速修复。 但是,如果您拥有的不是“键和值”,那么创建自己的自定义结构或类或定义一些 Tuple 类(如其他答案)更有意义。当您没有时,使用暗示您具有“键和值”的结构的不良做法。请避免误导以后必须阅读您的代码的人! 为不赞成投票道歉,因为有些人可能认为这是一个有用的解决方法(尽管根据我的上述评论,我认为这是误导性的),但最近的答案提供了单声道中完整元组实现的链​​接并且 nuget 应该高于这个答案。【参考方案6】:

是的,你可以在单声道中使用Tuple.cs:

您还需要依赖项:Tuples.csIStructuralComparable.csIStructuralEquatable.cs

你只是放了一个

#define NET_4_0

在每一个

#if NET_4_0

你去吧,一个功能完整的 System.Tuple 用于 .NET 2.0 的实现。

【讨论】:

提供的链接已失效 @Dav Evans:已更新。

以上是关于.NET Framework 3.5 的元组 (.NET 4) 等效项的主要内容,如果未能解决你的问题,请参考以下文章

我可以安全地安装 .Net Framework 3.5 SP1 而不要求我的客户升级他们的 .Net Framework 可分发包吗? (当前运行 3.5)

如果我有 .NET Framework 2.0 和 .NET Framework 3.5,是不是需要 .NET Framework 3?

text instalowanie 3.5 net framework#net3.5

安装.net framework 4.0 是不是需要.net framework 3.5?

查看4k对齐,激活.net framework 3.5

.Net Framework 4.0 安装程序是不是包含 .Net Framework 3.5?