将匿名类型转换为新的C#7元组类型

将匿名类型转换为新的C#7元组类型

问题描述:

新版本的C#具有实用的新功能Tuple Types:

The new version of C# is there, with the useful new feature Tuple Types:

public IQueryable<T> Query<T>();

public (int id, string name) GetSomeInfo() {
    var obj = Query<SomeType>()
        .Select(o => new {
            id = o.Id,
            name = o.Name,
        })
        .First();

    return (id: obj.id, name: obj.name);
}

有没有一种方法可以将匿名类型对象obj转换为要返回的元组,而无需按属性映射属性(假设属性名称匹配)?

Is there a way to convert my anonymous type object obj to the tuple that I want to return without mapping property by property (assuming that the names of the properties match)?

上下文位于ORM中,我的SomeType对象具有许多其他属性,并且映射到具有许多列的表中.我想执行一个仅包含ID和NAME的查询,因此我需要将匿名类型转换为元组,或者我需要ORM Linq提供程序知道如何理解元组并将与属性相关的列放在SQL select子句中.

The context is in a ORM, my SomeType object has a lot of other properties and it is mapped to a table with lot of columns. I wanna do a query that brings just ID and NAME, so I need to convert the anonymous type into a tuple, or I need that an ORM Linq Provider know how to understand a tuple and put the properties related columns in the SQL select clause.

简短的回答是否",在当前的C#7形式中,没有框架内的方法可以逐字地实现目标,因为您想实现以下目标:

The short answer is no, in the current form of C#7 there is no in-framework way to accomplish your goals verbatim, since you want to accomplish:

  • Linq到实体
  • 映射到列的子集
  • 通过直接映射到C#7元组来避免从自定义或匿名类型到C#7元组的属性映射.

由于Query<SomeType>公开了IQueryable,因此必须对表达式树.Select(x => new {})进行任何类型的投影.

Because Query<SomeType> exposes an IQueryable, any sort of projection must be made to an expression tree .Select(x => new {}).

打开roslyn问题,用于添加此支持,但没有存在.

There is an open roslyn issue for adding this support, but it doesn't exist yet.

因此,在添加此支持之前,您可以手动将匿名类型映射为元组,或者返回整个记录并将结果直接映射为元组,以避免两次映射,但这显然效率很低.

As a result, until this support is added, you can either manually map from an anonymous type to a tuple, or return the entire record and map the result to a tuple directly to avoid two mappings, but this is obviously inefficient.

尽管由于缺乏支持并且无法在.Select()投影中使用参数化构造函数,此限制目前已纳入Linq-to-Entities,但是Linq-to-NHibernate和Linq-to-Sql都允许使用黑客以在.Select()投影中创建新的System.Tuple的形式,然后返回带有

While this restriction is currently baked into Linq-to-Entities due to a lack of support and the inability to use parametered constructors in a .Select() projection, both Linq-to-NHibernate and Linq-to-Sql allow for a hack in the form of creating a new System.Tuple in the .Select() projection, and then returning a ValueTuple with the .ToValueTuple() extension method:

public IQueryable<T> Query<T>();

public (int id, string name) GetSomeInfo() {
    var obj = Query<SomeType>()
        .Select(o => new System.Tuple<int, string>(o.Id, o.Name))
        .First();

    return obj.ToValueTuple();
}

由于System.Tuple可以映射到表达式,因此您可以从表中返回数据的子集,并允许框架处理到C#7元组的映射.然后,您可以使用选择的任何命名约定来解构参数:

Since System.Tuple can be mapped to an expression, you can return a subset of data from your table and allow the framework to handle mapping to your C#7 tuple. You can then deconstruct the arguments with any naming convention you choose:

(int id, string customName) info = GetSomeInfo();
Console.Write(info.customName);