Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert anonymous type to new C# 7 tuple type

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

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)?

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.

like image 276
lmcarreiro Avatar asked Apr 13 '17 19:04

lmcarreiro


People also ask

How do you change to anonymous type?

Right-click and choose Refactor | Replace Anonymous Type with Named Class from the context menu. Choose ReSharper | Refactor | Convert | Anonymous to Named Type… from the main menu.

Do anonymous types work with Linq?

Use anonymous types with LINQThe Select clause in LINQ creates and returns an anonymous type as a result. The following code snippet illustrates this.

What is anonymous c#?

Anonymous types in C# are the types which do not have a name or you can say the creation of new types without defining them. It is introduced in C# 3.0. It is a temporary data type which is inferred based on the data that you insert in an object initializer.

Why anonymous types are preferred over tuples?

The ValueTuple types are mutable, whereas Tuple are read-only. Anonymous types can be used in expression trees, while tuples cannot.


1 Answers

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-to-entities
  • Mapping to a subset of columns
  • Avoiding property by property mapping from a custom or anonymous type to a C#7 tuple by mapping directly to a C#7 tuple.

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

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.


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

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); 
like image 115
David L Avatar answered Sep 21 '22 15:09

David L