C# 3.0 C#3.0元组等价物(适用于穷人)

C# 3.0 C#3.0元组等价物(适用于穷人),c#-3.0,tuples,C# 3.0,Tuples,我偶尔会在C#3.0中寻找模拟元组概念的方法。随着时间的推移,我已经有了各种“穷人”的实现,这里有一些: 基本对象数组: object[] poorTuple = new object[]{foo,bar,baz}; // basic object array 更强类型的,HoHoHo KeyValuePair<TypeA, KeyValuePair<TypeB, TypeC>> poorTuple; KeyValuePair-poorTuple; 实现一个可以使用

我偶尔会在C#3.0中寻找模拟元组概念的方法。随着时间的推移,我已经有了各种“穷人”的实现,这里有一些:

基本对象数组

object[] poorTuple = new object[]{foo,bar,baz}; // basic object array
更强类型的,HoHoHo

KeyValuePair<TypeA, KeyValuePair<TypeB, TypeC>> poorTuple;
KeyValuePair-poorTuple;
实现一个可以使用类型推断(从中提取)的类

公共静态类元组{
公共静态元组创建{
返回新元组(foo,bar);
}
}
//后来:
var data=Tuple.Create(“foo”,42);
问题:

  • 在C#3.0(或缺少数据结构的语言)中使用穷人元组的任何其他方法

  • 在C#3.0中获取元组的最佳方法是什么?如果有人有库推荐,欢迎使用

  • 在什么情况下(是的,对我来说是泛化的),创建一个特定的类型而不是像列表或元组这样的东西是有意义的?(寻找经验法则)


  • 您可以创建匿名类型,其功能类似于元组,但使用有用的名称除外:

    var itemsWithChildCounts 
        = myObjects.Select(x => new { Name = x.Name, Count = x.Children.Count() });
    

    我不喜欢C#中的类型推断,因为它被滥用得太多了。当然,这是一个非常酷的功能,但人们在这种情况下滥用它

    在这种情况下,我将显式地指定类型,以避免对类型的混淆(例如,42可能是长的、字节的或短的)

    那么,为什么不创建一个简单的元组类呢?它只需几行就可以实现。如果你很懒,你甚至可以为你的元组类写一些扩展方法。这使生活更容易,但也更干净


    你不明白用一个“奇特”的元组类来代替你介绍的泛型类有什么意义(除了类型推断)

    对于1-2:我更喜欢实现自己的元组类。你偷的是一个不错的实现。它应该很有效

    对于3:这是我的经验法则——只要您打算在多个方法中重用此功能(具有相同类型和相同含义),或者如果您在任何公共API中使用它,我认为是时候用您的特定类型实现一个“真实”类了

  • “实现一个类”方法是它将得到的最好的方法(无论如何,它应该在下一个版本的.NET中)
  • 不知道,我现在把它们放在我自己的班级图书馆里
  • <>我会考虑为他们创建一个适当的类,一旦他们暴露于公众(即当它们不再被用于仅仅为一个类存储相关的值)。
    既然你征求了我的意见,我会一直创建一个类型——我想不出一个不这样做的理由


    通常情况下,您会发现实际需要该类型(主要用途是在集合中存储两个项或从方法调用返回两个项——在这两种情况下,如果这些项不密切相关,则可能是做错了).

    以下是2007年4月版Visual Studio杂志中比尔·瓦格纳的通用元组代码

    公共结构元组:IEquatable
    {
    私有只读T1优先;
    公共T1优先
    {
    获取{return first;}
    }
    私有只读T2秒;
    公共T2秒
    {
    获取{return second;}
    } 
    公共元组(T1 f,T2 s)
    {
    第一个=f;
    秒=秒;
    }
    #区域可容纳成员
    公共布尔等于(元组其他)
    {
    先返回。等于(其他先返回)和
    第二,相等(其他,第二);
    }
    公共覆盖布尔等于(对象对象对象)
    {
    if(对象是元组)
    返回这个.Equals((元组)obj);
    其他的
    返回false;
    }
    公共覆盖int GetHashCode()
    {
    返回first.GetHashCode()ˆsecond.GetHashCode();
    }
    #端区
    }
    
    我认为在程序中引入新的值集是有意义的,创建一个新类型是很好的。例如,如果您正在编写一个复杂的计算器,则创建一个复杂的数字类型。如果您真的只想将几个变量“粘合”在一起,那么元组可能是更好的选择。假设您有一个从控制台收集两个数字的简单函数。。。您可能会这样做:

    static void GetNumbers(out int x, out int y) { ... }
    ...
    int x, y;
    GetNumbers(out x, out y);
    
    我认为当一个“getter”函数有一个返回值时,它通常是有意义的,但在这种情况下它没有意义,因为我不能真正有两个返回值。我可以去做一种叫做TwoNumber的新类型并使用它,但我认为这很快就会成为一个问题而不是解决方案。如果C#有元组,我可能可以做如下操作:

    static (int, int) GetNumbers() { ... }
    ...
    int x, y;
    (x, y) = GetNumbers();
    
    // this class is implemented much like yours only with C++
    template<typename T1, typename T2> class tuple { ... }
    ...
    template<typename T1, typename T2> tuple<T1, T2>& tie(T1 a, T2 b) { ... }
    ...
    template<typename T1, typename T2> tuple<T1, T2> get_numbers() { ... }
    ...
    int x, y;
    tie(x, y) = get_numbers();
    
    现在真正有趣的问题是:尽管C#没有这个特性,但我能用库自己实现它吗?您建议的代码只是一个开始,但不允许我像在第二个示例中那样分配。我不确定C++,但是在C++中,如果函数返回值是引用类型,函数调用可以是赋值操作符的左操作数,那么就可以在C++中真正接近这个。考虑以下事项:

    static (int, int) GetNumbers() { ... }
    ...
    int x, y;
    (x, y) = GetNumbers();
    
    // this class is implemented much like yours only with C++
    template<typename T1, typename T2> class tuple { ... }
    ...
    template<typename T1, typename T2> tuple<T1, T2>& tie(T1 a, T2 b) { ... }
    ...
    template<typename T1, typename T2> tuple<T1, T2> get_numbers() { ... }
    ...
    int x, y;
    tie(x, y) = get_numbers();
    
    <代码> //此类仅与C++实现 模板类元组{…} ... 模板元组&tie(T1-a,T2-b){…} ... 模板元组get_numbers(){…} ... int x,y; tie(x,y)=获取_个数字(); 我想说这真是太接近了。。。而不是
    (x,y)=
    我们有
    tie(x,y)=
    。如果您对实现细节感兴趣,我将向您介绍TR1库,我是在那里第一次了解到这一点的:


    所以要把这一切带回C#3.0。。。如您所示,我们当然可以创建一个通用的元组类,但是我们可以创建一个像tie这样的函数来“解包”C#中的元组吗?我没试过,听起来很有趣。如果没有类似的东西,我不愿意让一个C#元组库通过我的代码扩散

    匿名类型不能被传递到创建它们的方法之外,因此它们在r中的用处要小得多