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

例如:

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

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

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

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


当前回答

直到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()
    };

MichaelMocko回答得很好,

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

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

如果你使用。net framework < 4.7,上面的Line会给你一个编译时错误

因此,如果你有一个使用。net framework < 4.7的项目,你仍然想使用ValueTuple,而不是安装这个NuGet包

更新:

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

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

使用它

var (extension, fileName) = GetFile();

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

从这篇文章中复制我的答案,因为它更适合这里。

从c# v7.0开始,现在可以将元组属性命名为Item1、Item2等早先默认的名称。

命名元组字面量的属性:

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的答案。元组目前有几个陷阱:

你不能在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();
}

引用:

https://www.damirscorner.com/blog/posts/20181207-NoSupportForTuplesInExpressionTrees.html 将匿名类型转换为新的c# 7元组类型

你不能用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; })

引用:

c# 7元组和lambda

它们不会很好地连载

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

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

引用:

使值元组属性名在运行时可解析 c# 7元组支持(Newtonsoft.Json)

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

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