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

时间:2020-03-06 14:25:55  来源:igfitidea点击:

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

我想到的用例是:

Dictionary<Pair<string, int>, object>

或者

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

是否有内置类型,如"配对"或者"三重"?或者实现它的最佳方法是什么?

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

更新2我想也应该提醒一下,当我们将某些值用作字典中的键时,它应该是不可变的。

解决方案

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

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

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

三胞胎

一对

我最近遇到了它们,同时玩着ViewState解码

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;
}

是的,有System.Web.UI.Pair和System.Web.UI.Triplet(它们具有重载的创建者类型行为)!

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

Dictionary<KeyValuePair<string, int>, object>

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

我们可以将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。

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

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

如果我们不想创建自己的类,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以外的其他解决方案。

内置类

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

双人和三人组

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

另外,我们也可以解决
System.Collections.DictionaryEntry
充当基本对并具有以下优势的结构
在mscorlib中可用。但不利的是,这种结构不是
强类型。

对和三人组也可以以
System.Web.UI.Pair和
System.Web.UI.Triplet类。即使这些类存在于System.Web程序集中
它们可能非常适合Winforms开发。但是,这些类是
也不是强类型的,并且在某些情况下可能不适合,例如通用框架或者库。

高阶元组

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

如果我们已安装
语言,我们可以引用包含一组通用不可变的FSharp.Core.dll
Microsoft.Fsharp.Core.Tuple类
直到普通的六元组。但是,即使未修改的FSharp.Code.dll
可以重新分配,例如研究语言和正在进行的工作,
该解决方案可能仅在学术界感兴趣。

如果我们不想创建自己的课程而感到不舒服
引用Flibrary,一个不错的技巧可能在于扩展通用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; }
    }
}

框架和库

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

  • 迈克尔·L·佩里(Michael L Perry)的元组图书馆。

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

应当指出,.Net自己的KeyValuePair &lt;TKey,TValue>结构具有相对较慢的均等和哈希码方法。

假设我们不必担心,那么仍然存在代码难以理解的问题:

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;

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

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

尚未提及一种简单的解决方案。我们也可以只使用List &lt;T>。它内置,高效且易于使用。诚然,一开始它看起来有些怪异,但它可以完美地完成工作,尤其是对于大量元素而言。

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