方法和匿名类型

时间:2008-11-28 22:36:51

标签: c# extension-methods anonymous-types anonymous-methods

我知道您无法从方法返回匿名类型,但我想知道Select扩展方法如何返回匿名类型。它只是一个编译技巧吗?

修改

假设L是一个列表。这是如何工作的?

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

返回类型是IEnumerable<'a>其中'a = new {String Name}

4 个答案:

答案 0 :(得分:8)

嗯,这是泛型方法类型参数的正常类型推断。例如:

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

如果x是某个匿名类型的列表,或者lambda表达式的推断返回类型是匿名类型,则同样如此。不要忘记即使你不能明确说明使用匿名类型的变量的类型,它仍然 一个确定的类型,编译器已知。

答案 1 :(得分:8)

该类型实际上由调用者定义,因此它在调用函数的范围内 - 整齐地避免了“返回”匿名类型的问题。

这是通过通用类型推断实现的。 Select的签名为Select<Tsource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>IEnumerable<TSource>显然是源集合。 Func<Tsource, TResult>转换函数是编译器可以使用类型推断来声明匿名类型的地方。

换句话说,为了将Func<Tsource, TResult>传递给Select,您 - 调用者 - 必须定义TResult。这意味着Select没有返回由它定义的匿名类型 - 而是由你自己。

要模拟这一点,您只需让调用者定义类型:

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

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

答案 2 :(得分:5)

来自评论:“那么我将如何实施类似的方法”

这里你需要的是任何通用方法:

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

然后你可以:

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

编译器通过泛型类型推断提供<T>

有点厚颜无耻,但你甚至可以毫不费力地创建anon类型的实例:

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

同样,编译器通过lambda的返回值提供。

答案 3 :(得分:1)

Select的返回类型是通用的,它是从大多数情况下提供的lambda中推断出来的。

例如:

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

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

select的返回值基于我定义的匿名类型,并从lambda推导到委托,再推出到Select函数。在这种情况下,Select函数不知道或关心特定的匿名类型,因为从它的角度来看它是一个泛型类型。