【问题标题】:Methods and Anonymous Types方法和匿名类型
【发布时间】:2008-11-28 22:36:50
【问题描述】:

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

编辑

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

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

返回类型为 IEnumerable 其​​中 'a = new {String Name}

【问题讨论】:

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


    【解决方案1】:

    类型实际上是由调用者定义的,所以它在调用函数的范围内——巧妙地避免了“返回”匿名类型的问题。

    这是通过泛型类型推断来完成的。 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】:

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

      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 表达式的返回类型是匿名类型,情况也是如此。不要忘记,即使您不能显式声明使用匿名类型的变量的类型,它仍然具有编译器已知的明确类型。

      【讨论】:

      • 其实,你还能有一个匿名类型的列表吗?我认为他是在谈论您的示例中何时使用匿名类型而不是 int。
      • 是的,您可以轻松地拥有一个带有匿名类型元素的列表:new[] { new { Name="Jon" } }.ToList();
      • 还有其他获取列表的方法——例如,通过编写扩展方法并使用单个匿名实例(或将 lambda 转换为一个)将 T 转换为 List
      【解决方案3】:

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

      这里只需要任何通用方法:

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

      编译器通过泛型类型推断提供&lt;T&gt;

      有点厚颜无耻,但你甚至可以在没有实际创建匿名类型实例的情况下做到这一点:

      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 的返回值提供。

      【讨论】:

        【解决方案4】:

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

        例如:

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

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

        【讨论】:

        • 感谢古万特。那么我将如何实施类似的方法呢?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-03
        • 2010-09-08
        相关资源
        最近更新 更多