在C#中使用一对(三重等)值作为一个值的最佳方法是什么?

时间:2008-09-19 13:31:14

标签: c# generics data-structures tuples

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

我心中的用例:

Dictionary<Pair<string, int>, object>

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

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

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

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

16 个答案:

答案 0 :(得分:20)

内置类

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

对和三元组

通用 的 System.Collections.Generic.KeyValuePair class可以用作adhoc对实现。这是班级的 通用词典在内部使用。

或者,您可以使用 的 System.Collections.DictionaryEntry 结构,作为一个基本的对,具有的优势 在mscorlib中可用。然而,不利的是,这种结构不是 强烈打字。

Pairs和Triples也可以以形式出现 System.Web.UI.Pair System.Web.UI.Triplet 类。即使这些类存在于 System.Web 程序集中 它们可能非常适合winforms开发。但是,这些类是 也不是强类型,也可能不适用于某些场景,例如通用框架或库。

高阶元组

对于更高阶的元组,如果没有滚动自己的类,可能会 不是一个简单的解决方案。

如果您已经安装了 F# language,您可以引用包含一组通用不可变的 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; }
    }
}

框架和图书馆

之前已经解决了这个问题和通用框架 确实存在以下是一个这样的框架的链接:

答案 1 :(得分: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;
}

答案 2 :(得分:11)

快进到2010年,.NET 4.0现在支持n-tuples of arbitrary n。这些元组按预期实现结构上的平等和比较。

答案 3 :(得分:9)

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

Triplet

Pair

我最近遇到了他们,同时玩了viewstate解码

答案 4 :(得分:6)

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

答案 5 :(得分:3)

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

答案 6 :(得分: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>();

注意 System.Web -dll中存在 Triplet Pair 类,所以它不是非常适合除ASP.NET之外的其他解决方案。

答案 7 :(得分:2)

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

应该注意.Net自己的KeyValuePair<TKey,TValue>结构有relatively slow equality and hashcode methods

假设您不关心这个问题仍然存在代码最终难以理解的问题:

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;

答案 8 :(得分:2)

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

答案 9 :(得分:1)

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

要实现的第一个不可变的是 pair tuple 类。代码完全覆盖了测试,非常优雅。你可以查看它here。他们目前正致力于其他不可改变的替代方案,他们应该很快就会做好准备。

答案 10 :(得分:0)

没有内置插件,而是一对&lt; T,R&gt;创造阶级是微不足道的。

答案 11 :(得分:0)

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

答案 12 :(得分:0)

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

Dictionary<KeyValuePair<string, int>, object>

答案 13 :(得分:0)

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

答案 14 :(得分: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。

答案 15 :(得分:0)

还有Tuple&lt;&gt; F#中的类型;你只需要参考FSharp.Core.dll。