20

也就是说,我想要一个值的元组。

我心目中的用例:

Dictionary<Pair<string, int>, object>

或者

Dictionary<Triple<string, int, int>, object>

是否有内置类型,如 Pair 或 Triple?或者实现它的最佳方式是什么?

更新答案中描述了一些通用的元组实现,但是对于用作字典中的键的元组,您应该额外验证哈希码的正确计算。在另一个问题中对此有更多信息。

更新 2我想还值得提醒的是,当您使用某个值作为字典中的键时,它应该是不可变的。

4

16 回答 16

20

内置类

在某些特定情况下,.net 框架已经提供了您可以利用的类似元组的类。

对子和三人组

通用 System.Collections.Generic.KeyValuePair 类可用作临时对实现。这是通用 Dictionary 内部使用的类。

或者,您可以使用 System.Collections.DictionaryEntry 结构,该结构充当基本对并且具有在 mscorlib 中可用的优势。然而,不利的一面是这种结构不是强类型的。

Pairs 和 Triples 也以 System.Web.UI.PairSystem.Web.UI.Triplet类的形式提供。尽管这些类存在于System.Web程序集中,但它们可能非常适合 winforms 开发。但是,这些类也不是强类型的,并且可能不适合某些场景,例如通用框架或库。

高阶元组

对于高阶元组,除了滚动您自己的类之外,可能没有简单的解决方案。

如果您已安装 F# 语言,则可以引用 FSharp.Core.dll,其中包含一组通用不可变 Microsoft.Fsharp.Core.Tuple类,直至通用六元组。但是,即使可以重新分发未修改的FSharp.Code.dll ,F# 也是一种研究语言,并且还在进行中,因此该解决方案可能仅在学术界感兴趣。

如果您不想创建自己的类并且不喜欢引用 F# 库,那么一个巧妙的技巧可能是扩展通用 KeyValuePair 类,以便 Value 成员本身就是一个嵌套的 KeyValuePair。

例如,以下代码说明了如何利用 KeyValuePair 来创建三元组:

int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;

KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
   new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;

这允许根据需要将类扩展到任意级别。

KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string> quadruple =
    new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>();
KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string> quintuple =
    new KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string>();

自己动手

在其他情况下,您可能需要求助于滚动您自己的元组类,这并不难。

您可以像这样创建简单的结构:

struct Pair<T, R>
{
    private T first_;
    private R second_;

    public T First
    {
        get { return first_; }
        set { first_ = value; }
    }

    public R Second
    {
        get { return second_; }
        set { second_ = value; }
    }
}

框架和库

这个问题之前已经解决过,并且确实存在通用框架。下面是一个这样的框架的链接:

于 2008-09-19T15:20:48.790 回答
12
public struct Pair<T1, T2>
{
    public T1 First;
    public T2 Second;
}

public struct Triple<T1, T2, T3>
{
    public T1 First;
    public T2 Second;
    public T3 Third;
}
于 2008-09-19T13:35:41.227 回答
11

快进到 2010 年,.NET 4.0 现在支持任意 n 的 n 元组。这些元组按预期实现了结构相等和比较。

于 2010-08-15T00:49:31.157 回答
9

Pair 和 Triplet 是 .net 中的现有类,请参阅 msdn:

三胞胎

一对

我最近在玩视图状态解码时遇到了它们

于 2008-09-19T13:35:18.047 回答
6

我在 C# 中实现了一个元组库。访问http://www.adventuresinsoftware.com/generics/并单击“元组”链接。

于 2008-09-19T13:38:26.557 回答
3

我通常只是创建自己的结构,包含值。它通常更具可读性;)

于 2008-09-19T13:33:45.427 回答
2

如果您不想创建自己的类,KeyValuePair是最好的扩展类。

int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;

KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
   new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;

您可以将其扩展到任意多个级别。

KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string> quadruple =
   new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string>();

注意:类TripletPair存在于System.Web -dll 中,因此它不太适合 ASP.NET 以外的其他解决方案。

于 2008-09-19T13:44:17.773 回答
2

您可以相对轻松地创建自己的元组类,唯一可能会变得混乱的是您的相等性和哈希码覆盖(如果您要在字典中使用它们,这是必不可少的)。

需要注意的是,.Net 自己的KeyValuePair<TKey,TValue>struct 具有相对较慢的相等和 hashcode 方法

假设这不是您关心的问题,仍然存在代码最终难以弄清楚的问题:

public Tuple<int, string, int> GetSomething() 
{
    //do stuff to get your multi-value return
}

//then call it:
var retVal = GetSomething();

//problem is what does this mean?
retVal.Item1 / retVal.Item3; 
//what are item 1 and 3?

在大多数情况下,我发现创建特定的记录类更容易(至少在 C#4 使这个编译器具有魔力之前)

class CustomRetVal {
    int CurrentIndex { get; set; }
    string Message { get; set; }
    int CurrentTotal { get; set; }
}

var retVal = GetSomething();

//get % progress
retVal.CurrentIndex / retVal.CurrentTotal;
于 2008-09-19T16:14:22.250 回答
2

尚未提及一种简单的解决方案。您也可以只使用List<T>. 它是内置的,高效且易于使用。诚然,起初它看起来有点奇怪,但它完美地完成了它的工作,尤其是对于更多的元素。

于 2010-04-01T17:59:14.310 回答
1

NGenerics - 流行的 .Net 算法和数据结构库,最近在集合中引入了不可变数据结构。

第一个实现的不可变类是元组类。代码很好地覆盖了测试并且非常优雅。你可以在这里查看。他们目前正在研究其他不可变的替代方案,他们应该很快就会准备好。

于 2009-11-02T16:50:11.303 回答
0

没有内置插件,但创建 Pair<T,R> 类很简单。

于 2008-09-19T13:34:45.333 回答
0

是的,有 System.Web.UI.Pair 和 System.Web.UI.Triplet (它有一个重载的创建者来处理对类型的行为!)

于 2008-09-19T13:35:47.857 回答
0

对于第一种情况,我通常使用

Dictionary<KeyValuePair<string, int>, object>
于 2008-09-19T13:35:49.590 回答
0

没有内置的类。您可以使用KeyValuePair或推出自己的实现。

于 2008-09-19T13:35:55.003 回答
0

您可以使用 System.Collections.Generic.KeyValuePair 作为您的 Pair 实现。

或者你可以自己实现,它们并不难:

public class Triple<T, U, V>
{
  public T First {get;set;}
  public U Second {get;set;}
  public V Third {get;set;}
}

当然,你可能有一天会遇到 Triple(string, int, int) 与 Triple(int, int, string) 不兼容的问题。也许改用 System.Xml.Linq.XElement 。

于 2008-09-19T13:36:22.207 回答
0

F# 中还有 Tuple<> 类型;您只需要引用 FSharp.Core.dll。

于 2008-09-19T13:42:58.887 回答