How to access an element from an anonymous type

I have code like this

var results = (from c in Customers join o in Orders on c.Id equals o.CustomerId join p in Products on p.Id equals o.ProductId select new { CustomerId = c.Id, // this is a GUID OrderId = o.Id, // this is a GUID ProductName = p.ProductName, }).ToList(); 

Let's say I want to get a list of all the customer IDs who order a product with the name = foo My problem is that since this is an anonymous type, how can I refer to the product name in any Linq query that I want to run based on the results?

0
source share
4 answers
 var filteredResults = results.Where(r => r.ProductName == "X"); 

Compiler type inference will take care of this for you. Full answer to your question:

 var customerIds = results .Where(r => r.ProductName == "X") .Select(r => r.CustomerId) .Distinct() .ToList(); 

or

 var customerIds = (from r in results where r.ProductName == "X" select r.CustomerId) .Distinct() .ToList(); 

EDIT

Some thoughts on output type

To select lengths from a string sequence called list , you can call Select either using the classic static syntax method or as an extension method:

 Enumerable.Select<string, int>(list, s => s.Length) list.Select<string, int>(s => s.Length) 

Thanks to type inference, you don't need type arguments:

 Enumerable.Select(list, s => s.Length) list.Select(s => s.Length) 

In this case, the compiler can prove that the arguments of type string and int consider the arguments of the method, and it provides your type arguments on your behalf, without having to enter them into the source code.

For anonymous types, you cannot provide an argument of the first type because the type does not have a name to use in your source code (which means "anonymous", after all: "without a name",). (Thus, you can see that the anonymous types and output type were both critically important and closely related - prerequisites for implementing linq in the first place.)

If you check the IL for the anonymous type above, you will see that the compiler actually gave the type name (which contains characters that are illegal in C # identifiers). When you call Select , the compiler infers from the enumerated type ( IEnumerable<CrazilyNamedAnonymousType> ) that the argument of the first type must be an anonymous type, and, as in the string example, it passes this value on your behalf.

+5
source

Inside the method that generates this anonymous typed result, you can continue to reference the results as if you defined a specific type.

 var customersWithFoo = results.Where(r => r.ProductName == "foo") .Select(r => r.CustomerId); 

If you return the original result of the request from this method, and then want to request it further or otherwise access the elements programmatically, determine the type.

 class QueryResult { /* relevant properties */ } 

And then run the project into this type in the original request and return the sequence of this type from your method.

 public IEnumerable<QueryResult> GetResults() { var results = ... select new QueryResult { // properties }; return results; } 
+2
source

Following the comment:

I am confused about anonymous types

First, let's clearly define the "area." Region it is defined as an area of program text in which a type can refer to its unqualified name .

With this definition, it is obvious what a realm of anonymous type is. There is no area in the program text in which an anonymous type can refer to its name because it does not have a name. Anonymous types are not possible at all. You do not need to worry about its volume; he has no boundaries.

Fields of anonymous type also do not have scope, but for a different reason. Fields of anonymous type have names, but it is never legal to refer to them by their unqualified names, so the area of ​​each field is empty.

I am not sure that there will be visibility of this type within a method or class.

Again, let's clearly define our terms. An entity scope may include objects that define ad spaces. These ad spaces can declare objects that have the same name as the source object. These objects have their own areas, which can enter inside the area of ​​the source object.

In this situation, a more nested entity may “hide” a less nested entity. An entity that is not hidden in this way is considered “visible” in a specific text location.

An anonymous type has no scope, and it obviously cannot be hidden by name because it does not have a name. To ask if an anonymous type is “visible” or not is not a reasonable thing; "visibility" only makes sense for things that have names.

My thinking is that, given that this type is not declared anywhere, how can the compiler determine which type I am talking about?

The compiler notices every text location in which you use an anonymous type inside the program. If any of these places belong to anonymous types that have the same field names, the same field types and fields come in the same order, then these two locations are considered to be using the same anonymous type.

Then the compiler can produce one type for each of the unique anonymous types that you used in your assembly. The details of how this happens are fascinating (*). I suggest you pop your assembly with ILDASM to see how we do it if you're interested.

If you make the “same” anonymous type — the same names, types, and in the same order — in two different assemblies, then anonymous types will not be considered the same type. Anonymous types are not intended to be used at assembly boundaries.


(*) To me.

+2
source

Anonymous types will appear in intellisense as "normal" types. At compile time, a specific class is created that represents your anonymous type, so there are very few differences at run time.

Here is a query from your result set:

 var fooOrders = (from x in results where x.ProductName == "foo" select x.CustomerId); 
0
source

Source: https://habr.com/ru/post/1434742/


All Articles