在 C# 中使用一对(三重等)值作为一个值的最佳方法是什么?
-
01-07-2019 - |
题
也就是说,我想要一个值的元组。
我想到的用例:
Dictionary<Pair<string, int>, object>
或者
Dictionary<Triple<string, int, int>, object>
是否有像 Pair 或 Triple 这样的内置类型?或者实现它的最佳方法是什么?
更新 答案中描述了一些通用的元组实现,但是对于用作字典中的键的元组,您还应该验证哈希码的正确计算。另一个方面有更多信息 问题.
更新2 我想还值得提醒的是,当您使用某个值作为字典中的键时,它应该是不可变的。
解决方案
我用 C# 实现了一个元组库。访问 http://www.adventuresinsoftware.com/generics/ 并单击“元组”链接。
其他提示
内置类
在某些特定情况下,.net 框架已经提供了您可以利用的类似元组的类。
对和三人组
通用的System.Collections.Generic.KeyValuePair类可以用作临时对实现。这是通用词典内部使用的类。
或者,您也许可以凑合使用System.Collections.DictionaryEntry充当基本对的结构,具有在Mscorlib中可用的优势。然而,在偏低的一侧是,这种结构不是强烈键入的。
对和三元组也可以以以下形式提供:系统.Web.UI.Pair 和系统.Web.UI.三元组 类。尽管这些课程住在 系统.Web 组装它们可能非常适合Winforms开发。但是,这些类也不是强烈键入的,在某些情况下可能不适合使用,例如一般有目的的框架或库。
高阶元组
对于高阶元组,缺乏自己的课程,可能没有一个简单的解决方案。
如果您已经安装了F#语言, ,你可以参考 FSharp.Core.dll 包含一组通用的不可变的Microsoft.Fsharp.Core.Tuple 课程到通用分解。然而,即使未经修改 FSharp.Code.dll可以重新分配,F#是一种研究语言,并且正在进行中的工作,因此该解决方案只有在学术界才能引起人们的关注。
如果您不想创建自己的课程,并且不舒服引用f#库,那么一个漂亮的技巧可以包括扩展通用的keyValuepair类,以便值成员本身就是嵌套的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; }
}
}
框架和库
此问题之前已经解决了,并且确实存在通用框架。下面是一个这样的框架的链接:
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;
}
快进到 2010 年,.NET 4.0 现在支持 任意 n 的 n 元组. 。这些元组按预期实现结构相等和比较。
我通常只是创建自己的结构,包含值。它通常更具可读性;)
键值对 如果您不想创建自己的类,则这是最好的扩展类。
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>();
笔记: :课程 三胞胎 和 一对 存在于里面 系统.Web-dll,因此它不太适合除 ASP.NET 之外的其他解决方案。
您可以相对轻松地创建自己的元组类,唯一可能变得混乱的是您的等式和哈希码覆盖(如果您要在字典中使用它们,则这是必不可少的)。
需要注意的是.Net自己的 KeyValuePair<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;
尚未提及一种简单的解决方案。您也可以只使用 List<T>
. 。它是内置的,高效且易于使用。诚然,它一开始看起来有点奇怪,但它完美地完成了它的工作,特别是对于大量的元素。
NGenerics - 流行的 .Net 算法和数据结构库,最近推出 不可变的 数据结构到集合。
第一个实施的不可变的是 一对 和 元组 类。该代码经过充分测试,非常优雅。你可以检查一下 这里. 。他们目前正在研究其他不可变的替代方案,应该很快就会准备好。
没有内置函数,但创建 Pair<T,R> 类很简单。
是的,有 System.Web.UI.Pair 和 System.Web.UI.Triplet(它有一个用于 Pair 类型行为的重载创建者!)
对于第一种情况,我通常使用
Dictionary<KeyValuePair<string, int>, object>
没有为此的内置类。您可以使用 键值对 或推出您自己的实施。
您可以使用 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 。
F#中还有Tuple<>类型;你只需要引用FSharp.Core.dll。