views:

778

answers:

4

Hi,

I know that you cannot return anonymous types from methods but I am wondering how the Select extension method returns an anonymous type. Is it just a compiler trick?

Edit

Suppose L is a List. How does this work?

L.Select(s => new { Name = s })

The return type is IEnumerable<'a> where 'a = new {String Name}

+5  A: 

Well, it's normal type inference for generic method type arguments. For instance:

List<string> x = new List<string>();

// The compiler converts this:
x.Select(y => y.Length);

// Into this, using type inference:
Enumerable.Select<string, int>(x, y => y.Length);

The same would be true if x were a list of some anonymous type, or if the inferred return type of the lambda expression were an anonymous type. Don't forget that even though you can't explicitly state the type of a variable which uses an anonymous type, it still does have a definite type, known to the compiler.

Jon Skeet
Actually, can you even have a list of anonymous types? I think he was talking about when instead of int you have anonymous type in your example.
Guvante
Yes, you can easily have a list with an anonymous type element: new[] { new { Name="Jon" } }.ToList();
Jon Skeet
There are other ways of getting lists too - for example, by writing an extension method and using a single anon-instance (or a lambda to one) to turn a T to a List<T>
Marc Gravell
+1  A: 

The return type of Select is generic, and it is inferred from the lambda provided in most situations.

For example:

List<int> list = new List<int<();

var val = list.Select(x => new {value = x, mod = x % 10});

The return value of the select is based on the anonymous type I defined, and is extrapolated from the lambda, to a delegate, to the Select function. The Select function in this case does not know about or care about the particular anonymous type, as it is a generic type from its perspective.

Guvante
Thanks Guvante. So how would I go about implementing a similar method?
Rodrick Chapman
+2  A: 

From comment: " So how would I go about implementing a similar method"

All you need here is any generic method:

public List<T> Foo<T>(T template) { // doesn't actually use "template"
    return new List<T>();  // just an example
}

then you can have:

var list = Foo(new {Bar=1});

The compiler provides the <T> via generic type inference.

A bit cheeky, but you can even do it without actaully ever creating an instance of the anon-type:

public List<T> Foo<T>(Func<T> func) { // doesn't actually use "func"
    return new List<T>(); // just an example
}

var list = Foo(() => new {Bar = 1});

Again, the is provided by the compiler via the return value of the lambda.

Marc Gravell
+3  A: 

The type is actually defined by the caller, so it's in the scope of the calling function - neatly avoiding the issue of "returning" an anonymous type.

This is accomplished by generic type inference. The signature for Select is Select<Tsource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>. The IEnumerable<TSource> is, obviously, the source collection. The Func<Tsource, TResult> transformation function is where the compiler can use type inference to declare an anonymous type.

In other words, in order to pass a Func<Tsource, TResult> to Select, you - the caller - must define TResult. Which means Select isn't returning an anonymous type defined by it - but by you.

To emulate this, you just have to get the caller to define the type:

TResult ReturnAnonymousType<TResult>(Func<TResult> f) {
   return f();
}

Console.WriteLine(ReturnAnonymousType(
   () => return new { Text = "Hello World!" } // type defined here, before calling 
);
Mark Brackett