在元组类中比“;Item1", &;Item2"

是否有一种方法可以使用Tuple类,但在其中提供项目的名称?

例如:

public Tuple<int, int, int int> GetOrderRelatedIds()

它返回OrderGroupId、OrderTypeId、OrderSubTypeId和OrderRequirementId的id。

让我的方法的用户知道哪个是哪个就好了。(当您调用该方法时,结果为result。Item1,结果。第二条,结果。Item3 result.Item4。不清楚哪个是哪个。)

(我知道我可以创建一个类来保存所有这些id,但这些id已经有自己的类,它们生活在其中,为这个方法的返回值创建一个类似乎很愚蠢。)

210157 次浏览

直到c# 7.0,除了定义自己的类型,还没有办法做到这一点。

在。net 4中,你也许可以查看ExpandoObject,但是,不要在这种简单的情况下使用它,因为编译时错误会变成运行时错误。

class Program
{
static void Main(string[] args)
{
dynamic employee, manager;


employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;


manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;


WritePerson(manager);
WritePerson(employee);
}
private static void WritePerson(dynamic person)
{
Console.WriteLine("{0} is {1} years old.",
person.Name, person.Age);
// The following statement causes an exception
// if you pass the employee object.
// Console.WriteLine("Manages {0} people", person.TeamSize);
}
}
// This code example produces the following output:
// John Smith is 33 years old.
// Allison Brown is 42 years old.

另一个值得一提的是匿名类型 在一个方法中,但如果你想返回它,你需要创建一个类。

var MyStuff = new
{
PropertyName1 = 10,
PropertyName2 = "string data",
PropertyName3 = new ComplexType()
};

不,你不能命名元组成员。

中间的方法是使用ExpandoObject而不是Tuple。

下面是你所问问题的一个过于复杂的版本:

class MyTuple : Tuple<int, int>
{
public MyTuple(int one, int two)
:base(one, two)
{


}


public int OrderGroupId { get{ return this.Item1; } }
public int OrderTypeId { get{ return this.Item2; } }


}

为什么不直接创建一个类呢?

我想我会创建一个类,但另一种选择是输出参数。

public void GetOrderRelatedIds(out int OrderGroupId, out int OrderTypeId, out int OrderSubTypeId, out int OrderRequirementId)

因为你的元组只包含整数,你可以用Dictionary<string,int>来表示它

var orderIds = new Dictionary<string, int> {
{"OrderGroupId", 1},
{"OrderTypeId", 2},
{"OrderSubTypeId", 3},
{"OrderRequirementId", 4}.
};

但我也不建议这样做。

如果你的项目类型都不同,这里是一个类,我做了更直观地获得他们。

这个类的用法:

var t = TypedTuple.Create("hello", 1, new MyClass());
var s = t.Get<string>();
var i = t.Get<int>();
var c = t.Get<MyClass>();

源代码:

public static class TypedTuple
{
public static TypedTuple<T1> Create<T1>(T1 t1)
{
return new TypedTuple<T1>(t1);
}


public static TypedTuple<T1, T2> Create<T1, T2>(T1 t1, T2 t2)
{
return new TypedTuple<T1, T2>(t1, t2);
}


public static TypedTuple<T1, T2, T3> Create<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
{
return new TypedTuple<T1, T2, T3>(t1, t2, t3);
}


public static TypedTuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4)
{
return new TypedTuple<T1, T2, T3, T4>(t1, t2, t3, t4);
}


public static TypedTuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{
return new TypedTuple<T1, T2, T3, T4, T5>(t1, t2, t3, t4, t5);
}


public static TypedTuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{
return new TypedTuple<T1, T2, T3, T4, T5, T6>(t1, t2, t3, t4, t5, t6);
}


public static TypedTuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{
return new TypedTuple<T1, T2, T3, T4, T5, T6, T7>(t1, t2, t3, t4, t5, t6, t7);
}


public static TypedTuple<T1, T2, T3, T4, T5, T6, T7, T8> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{
return new TypedTuple<T1, T2, T3, T4, T5, T6, T7, T8>(t1, t2, t3, t4, t5, t6, t7, t8);
}


}


public class TypedTuple<T>
{
protected Dictionary<Type, object> items = new Dictionary<Type, object>();


public TypedTuple(T item1)
{
Item1 = item1;
}


public TSource Get<TSource>()
{
object value;
if (this.items.TryGetValue(typeof(TSource), out value))
{
return (TSource)value;
}
else
return default(TSource);
}


private T item1;
public T Item1 { get { return this.item1; } set { this.item1 = value; this.items[typeof(T)] = value; } }
}


public class TypedTuple<T1, T2> : TypedTuple<T1>
{
public TypedTuple(T1 item1, T2 item2)
: base(item1)
{
Item2 = item2;
}


private T2 item2;
public T2 Item2 { get { return this.item2; } set { this.item2 = value; this.items[typeof(T2)] = value; } }
}


public class TypedTuple<T1, T2, T3> : TypedTuple<T1, T2>
{
public TypedTuple(T1 item1, T2 item2, T3 item3)
: base(item1, item2)
{
Item3 = item3;
}


private T3 item3;
public T3 Item3 { get { return this.item3; } set { this.item3 = value; this.items[typeof(T3)] = value; } }
}


public class TypedTuple<T1, T2, T3, T4> : TypedTuple<T1, T2, T3>
{
public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4)
: base(item1, item2, item3)
{
Item4 = item4;
}


private T4 item4;
public T4 Item4 { get { return this.item4; } set { this.item4 = value; this.items[typeof(T4)] = value; } }
}


public class TypedTuple<T1, T2, T3, T4, T5> : TypedTuple<T1, T2, T3, T4>
{
public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
: base(item1, item2, item3, item4)
{
Item5 = item5;
}


private T5 item5;
public T5 Item5 { get { return this.item5; } set { this.item5 = value; this.items[typeof(T5)] = value; } }
}


public class TypedTuple<T1, T2, T3, T4, T5, T6> : TypedTuple<T1, T2, T3, T4, T5>
{
public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
: base(item1, item2, item3, item4, item5)
{
Item6 = item6;
}


private T6 item6;
public T6 Item6 { get { return this.item6; } set { this.item6 = value; this.items[typeof(T6)] = value; } }
}


public class TypedTuple<T1, T2, T3, T4, T5, T6, T7> : TypedTuple<T1, T2, T3, T4, T5, T6>
{
public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
: base(item1, item2, item3, item4, item5, item6)
{
Item7 = item7;
}


private T7 item7;
public T7 Item7 { get { return this.item7; } set { this.item7 = value; this.items[typeof(T7)] = value; } }
}


public class TypedTuple<T1, T2, T3, T4, T5, T6, T7, T8> : TypedTuple<T1, T2, T3, T4, T5, T6, T7>
{
public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8)
: base(item1, item2, item3, item4, item5, item6, item7)
{
Item8 = item8;
}


private T8 item8;
public T8 Item8 { get { return this.item8; } set { this.item8 = value; this.items[typeof(T8)] = value; } }
}

您可以编写一个包含元组的类。

您需要重写Equals和GetHashCode函数

和==和!=操作符。

class Program
{
public class MyTuple
{
private Tuple<int, int> t;


public MyTuple(int a, int b)
{
t = new Tuple<int, int>(a, b);
}


public int A
{
get
{
return t.Item1;
}
}


public int B
{
get
{
return t.Item2;
}
}


public override bool Equals(object obj)
{
return t.Equals(((MyTuple)obj).t);
}


public override int GetHashCode()
{
return t.GetHashCode();
}


public static bool operator ==(MyTuple m1, MyTuple m2)
{
return m1.Equals(m2);
}


public static bool operator !=(MyTuple m1, MyTuple m2)
{
return !m1.Equals(m2);
}
}


static void Main(string[] args)
{
var v1 = new MyTuple(1, 2);
var v2 = new MyTuple(1, 2);


Console.WriteLine(v1 == v2);


Dictionary<MyTuple, int> d = new Dictionary<MyTuple, int>();
d.Add(v1, 1);


Console.WriteLine(d.ContainsKey(v2));
}
}

将返回:

真正的

真正的

为什么每个人都让生活如此艰难。元组用于临时数据处理。一直使用元组会使代码在某些时候非常难以理解。为一切创建类最终会使你的项目膨胀。

然而,这是关于平衡的……

你的问题似乎需要一门课程来解决。为了完整起见,下面这个类还包含构造函数。


这是合适的模式

  • 自定义数据类型
    • 没有进一步的功能。getter和setter也可以通过代码进行扩展,以“_orderGroupId”的名称模式获取/设置私有成员,同时还可以执行函数代码。
    • 李< / ul > < / >
    • 包括构造函数。如果所有属性是强制的,你也可以选择只包含一个构造函数。
    • 如果希望使用所有构造函数,像这样冒泡是避免重复代码的正确模式。

    public class OrderRelatedIds
    {
    public int OrderGroupId { get; set; }
    public int OrderTypeId { get; set; }
    public int OrderSubTypeId { get; set; }
    public int OrderRequirementId { get; set; }
    
    
    public OrderRelatedIds()
    {
    }
    public OrderRelatedIds(int orderGroupId)
    : this()
    {
    OrderGroupId = orderGroupId;
    }
    public OrderRelatedIds(int orderGroupId, int orderTypeId)
    : this(orderGroupId)
    {
    OrderTypeId = orderTypeId;
    }
    public OrderRelatedIds(int orderGroupId, int orderTypeId, int orderSubTypeId)
    : this(orderGroupId, orderTypeId)
    {
    OrderSubTypeId = orderSubTypeId;
    }
    public OrderRelatedIds(int orderGroupId, int orderTypeId, int orderSubTypeId, int orderRequirementId)
    : this(orderGroupId, orderTypeId, orderSubTypeId)
    {
    OrderRequirementId = orderRequirementId;
    }
    }
    

    或者,如果你想让它非常简单:你也可以使用类型初始化器:

    OrderRelatedIds orders = new OrderRelatedIds
    {
    OrderGroupId = 1,
    OrderTypeId = 2,
    OrderSubTypeId = 3,
    OrderRequirementId = 4
    };
    
    
    public class OrderRelatedIds
    {
    public int OrderGroupId;
    public int OrderTypeId;
    public int OrderSubTypeId;
    public int OrderRequirementId;
    }
    

我会把项目名称写在总结.. 因此,通过将鼠标悬停在helloworld()函数上,文本将显示hello = Item1和world = Item2

 helloworld("Hi1,Hi2");


/// <summary>
/// Return hello = Item1 and world Item2
/// </summary>
/// <param name="input">string to split</param>
/// <returns></returns>
private static Tuple<bool, bool> helloworld(string input)
{
bool hello = false;
bool world = false;
foreach (var hw in input.Split(','))
{
switch (hw)
{
case "Hi1":
hello= true;
break;
case "Hi2":
world= true;
break;
}


}
return new Tuple<bool, bool>(hello, world);
}

在c# 7.0 (Visual Studio 2017)中,有一个新的结构可以做到这一点:

(string first, string middle, string last) LookupName(long id)

这是非常烦人的,我希望未来的c#版本能够解决这一需求。我发现最简单的方法是使用不同的数据结构类型,或者重命名“items”,以使您和其他阅读您的代码的人能够正常阅读。

Tuple<ApiResource, JSendResponseStatus> result = await SendApiRequest();
ApiResource apiResource = result.Item1;
JSendResponseStatus jSendStatus = result.Item2;

帖子中复制我的答案,因为它更适合这里。

从c# v7.0开始,现在可以为元组属性命名,而以前通常默认为Item1Item2等名称。

命名元组字面量的属性:

var myDetails = (MyName: "Foo", MyAge: 22, MyFavoriteFood: "Bar");
Console.WriteLine($"Name - {myDetails.MyName}, Age - {myDetails.MyAge}, Passion - {myDetails.MyFavoriteFood}");

控制台的输出:

Name - Foo, Age - 22, Passion - Bar

从方法返回元组(具有命名属性):

static void Main(string[] args)
{
var empInfo = GetEmpInfo();
Console.WriteLine($"Employee Details: {empInfo.firstName}, {empInfo.lastName}, {empInfo.computerName}, {empInfo.Salary}");
}


static (string firstName, string lastName, string computerName, int Salary) GetEmpInfo()
{
//This is hardcoded just for the demonstration. Ideally this data might be coming from some DB or web service call
return ("Foo", "Bar", "Foo-PC", 1000);
}

控制台的输出:

Employee Details: Foo, Bar, Foo-PC, 1000

创建具有命名属性的元组列表

var tupleList = new List<(int Index, string Name)>
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};


foreach (var tuple in tupleList)
Console.WriteLine($"{tuple.Index} - {tuple.Name}");

控制台输出:

1 - cow
5 - chickens
1 - airplane

请注意:本文中的代码片段使用c# v6的字符串插值特性作为详细的在这里

MichaelMocko回答得很好,

但我想补充一些我必须弄清楚的东西

(string first, string middle, string last) LookupName(long id)

如果你正在使用.net framework <4.7,上面的Line会给你编译时错误

因此,如果你有一个使用.net framework <4.7的项目,你仍然想使用ValueTuple,那么解决方案将安装this NuGet包

更新:

从方法返回Named tuple并使用它的示例

public static (string extension, string fileName) GetFile()
{
return ("png", "test");
}

使用它

var (extension, fileName) = GetFile();


Console.WriteLine(extension);
Console.WriteLine(fileName);

c# 7元组的例子

var tuple = TupleExample(key, value);


private (string key1, long value1) ValidateAPIKeyOwnerId(string key, string value)
{
return (key, value);
}
if (!string.IsNullOrEmpty(tuple.key1) && tuple.value1 > 0)
{
//your code


}

只是补充一下@MichaelMocko的答案。元组目前有几个陷阱:

你不能在EF表达式树中使用它们

例子:

public static (string name, string surname) GetPersonName(this PersonContext ctx, int id)
{
return ctx.Persons
.Where(person => person.Id == id)
// Selecting as Tuple
.Select(person => (person.Name, person.Surname))
.First();
}

使用“表达式树可能不包含元组字面值”编译将失败;错误。不幸的是,表达式树API在向语言中添加元组时并没有扩展对元组的支持。

跟踪(并投票)此问题的更新:https://github.com/dotnet/roslyn/issues/12897

为了解决这个问题,你可以先将其转换为匿名类型,然后将值转换为元组:

// Will work
public static (string name, string surname) GetPersonName(this PersonContext ctx, int id)
{
return ctx.Persons
.Where(person => person.Id == id)
.Select(person => new { person.Name, person.Surname })
.ToList()
.Select(person => (person.Name, person.Surname))
.First();
}

另一种选择是使用ValueTuple。创建:

// Will work
public static (string name, string surname) GetPersonName(this PersonContext ctx, int id)
{
return ctx.Persons
.Where(person => person.Id == id)
.Select(person => ValueTuple.Create(person.Name, person.Surname))
.First();
}


引用:

你不能用lambda解构它们

有一个添加支持的提议:https://github.com/dotnet/csharplang/issues/258

例子:

public static IQueryable<(string name, string surname)> GetPersonName(this PersonContext ctx, int id)
{
return ctx.Persons
.Where(person => person.Id == id)
.Select(person => ValueTuple.Create(person.Name, person.Surname));
}


// This won't work
ctx.GetPersonName(id).Select((name, surname) => { return name + surname; })


// But this will
ctx.GetPersonName(id).Select(t => { return t.name + t.surname; })

引用:

它们不会很好地连载

using System;
using Newtonsoft.Json;


public class Program
{
public static void Main() {
var me = (age: 21, favoriteFood: "Custard");
string json = JsonConvert.SerializeObject(me);


// Will output {"Item1":21,"Item2":"Custard"}
Console.WriteLine(json);
}
}

元组字段名仅在编译时可用,并在运行时完全删除。

引用:

(double, int) t1 = (4.5, 3);
Console.WriteLine($"Tuple with elements {t1.Item1} and {t1.Item2}.");
// Output:
// Tuple with elements 4.5 and 3.


(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.

来自Docs: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples

到今天为止,就是这么简单。而不是使用Tuple关键字

public Tuple<int, int, int int> GetOrderRelatedIds()

用这个。

public (int alpha, int beta, int candor) GetOrderRelatedIds()

得到这样的值。

var a = GetOrderRelatedIds();
var c = a.alpha;

TL:→博士__abc0可以自定义字段名,而__abc1不能。

澄清一下,在c# 7.0及更高版本中有两种不同类型的元组。

系统。元组 而且 系统。ValueTuple < / p >

当你通过Tuple<...>类声明一个元组时:

public Tuple<int, string, int> GetUserInfo();

你声明了一个< >强Tuple < / >强 对象数据类型。

当你通过圆括号声明一个元组时:

public (int id, string name, int age) GetUserInfo();

你声明了一个< >强ValueTuple < / >强 价值数据类型。

每一个都有不同的功能和行为。在你的问题中,你的方法返回一个System.Tuple对象。

不幸的是,通过System.Tuple类创建的Tuple对象没有内置功能来给每个属性一个自定义名称。它们总是默认为ItemN,这取决于它们包含多少属性。

另一方面,System.ValueTuple值可以包含自定义命名字段。

要了解更多信息,可以参考元组类型(c#参考)和/或上面每个类的链接。但从本质上讲,文档强调的两种不同类型元组的一些关键区别是:

c#元组,由System.ValueTuple类型支持,是不同的 由System.Tuple类型表示的元组。主要的 差异如下:

  • System.ValueTuple类型是值类型。System.Tuple类型是引用类型。
  • System.ValueTuple类型是可变的。System.Tuple类型是不可变的。
  • System.ValueTuple类型的数据成员是字段。System.Tuple类型的数据成员是属性。

因此,如果你的方法需要返回一个System.Tuple对象,或者你更想要该类型对象的行为,那么在写这篇文章时,你无法实现你想要的。然而,如果你的方法可以返回一个System.ValueTuple值,那么你可以在返回值中为它指定自定义命名字段。

为什么不使用多个返回而不是使用元组

var handler = GenerateFromMethod1(hits);
Process(handler.string1, handler.string1);


private static (string string1, string string2) GenerateFromMethod1()
{


}