有没有办法使用Tuple类,但提供其中的项目名称?
例如:
public Tuple<int, int, int int> GetOrderRelatedIds()
返回OrderGroupId,OrderTypeId,OrderSubTypeId和OrderRequirementId的ID。
让我的方法的用户知道哪个是哪个是很好的。 (当你调用方法时,结果是result.Item1,result.Item2,result.Item3,result.Item4。不清楚哪一个是哪个。)
(我知道我可以创建一个类来保存所有这些ID,但是这些ID已经拥有了他们自己的类,并且为这个方法的返回值创建一个类看起来很傻。)
答案 0 :(得分:201)
在C#7.0(Visual Studio 2017)中,有一种新结构可以做到这一点:
(string first, string middle, string last) LookupName(long id)
答案 1 :(得分:50)
直到C#7.0,没有办法做到这一点,没有办法定义你自己的类型。
答案 2 :(得分:31)
这是你要问的过于复杂的版本:
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; } }
}
为什么不上课?
答案 3 :(得分:12)
使用.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.
其他值得一提的是方法中的anonymous type ,但如果要返回它,则需要创建一个类。
var MyStuff = new
{
PropertyName1 = 10,
PropertyName2 = "string data",
PropertyName3 = new ComplexType()
};
答案 4 :(得分:3)
如果您的项目类型各不相同,请参阅此类课程,以便更直观地了解这些课程。
此课程的用法:
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; } }
}
答案 5 :(得分:2)
不,你不能命名元组成员。
中间是使用ExpandoObject而不是元组。
答案 6 :(得分:1)
MichaelMocko的回答很棒,
但是我想添加一些我必须弄清楚的东西
(string first, string middle, string last) LookupName(long id)
如果您使用的是 .net框架<4.7 ,则在Line之上,会出现编译时错误。
因此,如果您有一个正在使用 .net Framework <4.7 的项目,但仍要使用ValueTuple而不是workAround将安装 this nuget软件包
答案 7 :(得分:1)
从this帖子中再现我的回答,因为它更适合这里。
现在可以启动C#v7.0,可以将之前用来默认为Item1
,Item2
等名称的元组属性命名为。
命名Tuple Literals的属性:
var myDetails = (MyName: "RBT_Yoga", MyAge: 22, MyFavoriteFood: "Dosa");
Console.WriteLine($"Name - {myDetails.MyName}, Age - {myDetails.MyAge}, Passion - {myDetails.MyFavoriteFood}");
控制台上的输出:
姓名 - RBT_Yoga,年龄 - 22岁,激情 - Dosa
从方法中返回元组(具有命名属性):
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 ("Rasik", "Bihari", "Rasik-PC", 1000);
}
控制台上的输出:
员工详情:Rasik,Bihari,Rasik-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 - 牛 5 - 鸡 1 - 飞机
我希望我已经涵盖了一切。如果有什么我错过了,请在评论中给我一个反馈。
注意:我的代码段使用了C#v7的字符串插值功能,详细内容为here。
答案 8 :(得分:0)
截至今天,就是这么简单。而不是使用 Tuple 关键字
public Tuple<int, int, int int> GetOrderRelatedIds()
使用这个。
public (int alpha, int beta, int candor) GetOrderRelatedIds()
获取这样的值。
var a = GetOrderRelatedIds();
var c = a.alpha;
答案 9 :(得分:0)
(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.
From Docs https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples
答案 10 :(得分:0)
只需添加到@MichaelMocko答案即可。元组目前有一些陷阱:
示例:
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.Create:
// 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();
}
参考:
有人建议添加支持: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);
}
}
元组字段名称仅在编译时可用,并在运行时完全清除。
参考:
答案 11 :(得分:0)
这非常烦人,我希望未来的C#版本能满足这种需求。我发现最简单的方法是使用不同的数据结构类型,或者重命名“items”以获得理智,并重新理解其他人阅读代码的理智。
{{1}}
答案 12 :(得分:0)
我会在摘要中写出项目名称.. 所以通过将鼠标悬停在函数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);
}
答案 13 :(得分:0)
为什么每个人都如此努力地生活。元组用于相当临时数据处理。一直使用元组会使代码在某些时候很难理解。为一切创建类最终可能会使您的项目膨胀。
关于平衡,但是......
你的问题似乎是你想要上课的。并且为了完整起见,下面的这个类也包含构造函数。
这是
的正确模式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;
}
答案 14 :(得分:0)
我想我会创建一个类,但另一个选择是输出参数。
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}.
};
但我也不建议这样做。
答案 15 :(得分:-1)
你可以编写一个包含元组的类。
您需要覆盖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));
}
}
将返回:
真
真
答案 16 :(得分:-2)
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
}