在Tuple类中比"Item1","Item2"更好地命名

Vac*_*ano 180 c# tuples c#-4.0

有没有办法使用Tuple类,但提供其中的项目名称?

例如:

public Tuple<int, int, int int> GetOrderRelatedIds()
Run Code Online (Sandbox Code Playgroud)

返回OrderGroupId,OrderTypeId,OrderSubTypeId和OrderRequirementId的id.

让我的方法的用户知道哪个是哪个是很好的.(当你调用方法时,结果是result.Item1,result.Item2,result.Item3,result.Item4.不清楚哪一个是哪个.)

(我知道我可以创建一个类来保存所有这些ID,但是这些ID已经拥有了他们自己的类,并为这个方法的返回值创建一个类看起来很傻.)

Mic*_*cko 240

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

(string first, string middle, string last) LookupName(long id)
Run Code Online (Sandbox Code Playgroud)

  • 语法是`List <(int first,int second)>`.我必须从NuGet下载System.ValueTuple包才能在Visual Studio 2017中使用它. (57认同)
  • 应该注意的是,C#7的`ValueTuple`虽然通常很好,但是是一个可变值类型(struct),而`Tuple`是一个不可变的引用类型(class).据我所知,没有办法获得带有友好项目名称的引用类型`Tuple`. (10认同)
  • 创建值`return(first:first,middle:middle,last:last);` (9认同)
  • 或仅:.NET 4.7.1中的return(第一,中间,最后);(对于4.7.0不确定) (3认同)

Mar*_*lug 52

直到C#7.0,没有办法做到这一点,无法定义自己的类型.

  • 我无法相信这个答案被接受为40分.你至少可以展示一个具有适当构造函数的类如何能够替代它. (11认同)
  • Q'有c#4作为标签,所以尽管这个答案很短,但仍然是正确的. (8认同)
  • C#7发布后,可以这样做:https://msdn.microsoft.com/en-us/magazine/mt595758.aspx (2认同)

sco*_*ttm 32

这是你要问的过于复杂的版本:

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

}
Run Code Online (Sandbox Code Playgroud)

为什么不上课?

  • 这种方法的另一个缺点是Item1和Item2仍然是MyTuple上的公共属性 (7认同)
  • 我看到的一个小优点是它自动实现了equals运算符,如果项目全部相等则检查2个实例是否相等. (5认同)
  • @deathrace Tuple本身就是类,所以如果你想直接继承`Tuple <T,T2>`你就不能成为一个结构. (3认同)
  • 我可能错了,但我主要使用元组,无论我想要返回一个对象,但不想定义一个特定的类. (3认同)
  • 在这种情况下,结构会比类更好吗? (2认同)

Sna*_*nap 23

TL:DR -> System.ValueTuples 可以为字段指定自定义名称,而System.Tuples 则不能。

澄清一下,C# 7.0 及更高版本中有 2 种不同类型的元组。在此之前,只有 1 种单一类型的元组可用。

System.Tuple(这是 C# 7 之前存在的元组的原始类型)和 System.ValueTuple(C# 7 中添加的元组类型)

当您通过类声明元Tuple<...>组时:

public Tuple<int, string, int> GetUserInfo();
Run Code Online (Sandbox Code Playgroud)

您正在声明对象数据类型。Tuple

当您通过括号声明元组时:

public (int id, string name, int age) GetUserInfo();
Run Code Online (Sandbox Code Playgroud)

您正在声明一个数据类型。ValueTuple

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

不幸的是,通过类创建的 Tuple 对象System.Tuple没有内置功能来为每个属性提供自定义名称。它们始终默认为 Item N,具体取决于它们包含的属性数量。

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

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

由类型支持的 C# 元组System.ValueTuple与由类型表示的元组不同System.Tuple。主要区别如下:

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

因此,如果您的方法需要返回一个System.Tuple对象,或者您更希望该类型对象的行为,那么在编写本文时,您将无法实现您想要的。但是,如果您的方法可以返回一个System.ValueTuple值,那么您可以在返回值中为其指定自定义命名字段。


Geo*_*ett 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.
Run Code Online (Sandbox Code Playgroud)

别的东西值得一提的是匿名类型 的方法中,但你需要创建一个类,如果你想退货.

var MyStuff = new
    {
        PropertyName1 = 10,
        PropertyName2 = "string data",
        PropertyName3 = new ComplexType()
    };
Run Code Online (Sandbox Code Playgroud)


Mih*_*ave 6

MichaelMocko 回答很棒,

但我想添加一些我必须弄清楚的事情

(string first, string middle, string last) LookupName(long id)
Run Code Online (Sandbox Code Playgroud)

如果您使用的是.net framework < 4.7,上面的行会给您编译时错误

因此,如果您有一个使用.net framework < 4.7的项目,并且您仍然想使用 ValueTuple,那么 workAround 将安装NuGet 包

更新:

从方法返回命名元组并使用它的示例

public static (string extension, string fileName) GetFile()
{
    return ("png", "test");
}
Run Code Online (Sandbox Code Playgroud)

使用它

var (extension, fileName) = GetFile();

Console.WriteLine(extension);
Console.WriteLine(fileName);
Run Code Online (Sandbox Code Playgroud)


RBT*_*RBT 5

本文中转载我的答案,因为这里比较合适。

启动C#7.0版现在可以命名较早使用默认名称类似的元组的属性Item1Item2等等。

命名元组文字的属性

var myDetails = (MyName: "RBT_Yoga", MyAge: 22, MyFavoriteFood: "Dosa");
Console.WriteLine($"Name - {myDetails.MyName}, Age - {myDetails.MyAge}, Passion - {myDetails.MyFavoriteFood}");
Run Code Online (Sandbox Code Playgroud)

控制台上的输出:

名字-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);
}
Run Code Online (Sandbox Code Playgroud)

控制台上的输出:

员工详细信息: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}");
Run Code Online (Sandbox Code Playgroud)

在控制台上输出:

1-牛5-鸡1-飞机

我希望我已经涵盖了所有内容。如果有任何我想念的东西,请在评论中给我反馈。

注意:我的代码段使用的是C#v7的字符串插值功能,如此处所述


Eug*_*hov 5

只是添加到 @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();
}
Run Code Online (Sandbox Code Playgroud)

这将无法编译并出现“表达式树可能不包含元组文字”错误。不幸的是,当将元组添加到语言中时,表达式树 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();
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用 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();
}

Run Code Online (Sandbox Code Playgroud)

参考:

你不能在 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; })
Run Code Online (Sandbox Code Playgroud)

参考:

他们不会很好地连载

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); 
    }
}
Run Code Online (Sandbox Code Playgroud)

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

参考:


Qud*_*dus 5

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

public Tuple<int, int, int int> GetOrderRelatedIds()
Run Code Online (Sandbox Code Playgroud)

用这个。

public (int alpha, int beta, int candor) GetOrderRelatedIds()
Run Code Online (Sandbox Code Playgroud)

获取这样的值。

var a = GetOrderRelatedIds();
var c = a.alpha;
Run Code Online (Sandbox Code Playgroud)