【问题标题】:C# generics: failure of generic type inference means I cannot use anonymous typeC#泛型:泛型类型推断失败意味着我不能使用匿名类型
【发布时间】:2011-05-27 21:14:02
【问题描述】:

我有一个类 Exporter,它有一个通用方法,它接受 IEnumerable<T> 并通过使用反射枚举其属性值来创建导出文档:

  public class Exporter
  {
    public string Export<T>(IEnumerable<T> enumerable)
    {
      //Implementation omitted
    }
  }

由于泛型类型推断,我可以为它提供一个匿名集合类型。注意下面的方法调用中没有泛型参数:

string fooString =
        new Exporter().Export(new List<Foo>()
                                {
                                  new Foo() {Name = "cats", NumberOfHams = 1},
                                  new Foo() {Name = "dogs", NumberOfHams = 8}
                                }
                       .Select(x => new { TwiceTheHams = x.NumberOfHams * 2 }));

我们都喜欢 C#3。但是,我想调整这个类,以便我可以输入有关导出文档中列的更多信息,例如宽度。

我在导出类中创建了一个新方法,如下所示:

public string Export<T>(IEnumerable<T> enumerable, IEnumerable<ColumnDetails<T>> columnDetails)
    {
      //Implementation omitted
    }

理想情况下,语法应该是这样的,其中foos 的类型是IEnumerable&lt;Foo&gt;

fooString = new Exporter().Export(foos,
                                      new List<ColumnDetails<Foo>>
                                        {
                                          new ColumnDetails<Foo>(x => x.Name, 12),
                                          new ColumnDetails<Foo>(x => x.NumberOfHams, 4),
                                        });

但是,当我如上所述调用新的Export() 重载时,泛型类型推断似乎不够聪明,无法推断ColumnDetails&lt;T&gt; 的泛型参数T 应该与泛型相同IEnumerable 的参数 T。这意味着我必须将List&lt;ColumnDetails&lt;Foo&gt;&gt; 指定为参数,因此我不能将它与匿名集合一起使用。

我对泛型和类型推断非常陌生。我正在尝试做的事情可能吗?我需要以某种方式重组代码吗?

编辑:这是我不能做的,因为 Visual Studio 需要 ColumnDetails 的通用参数,而我没有:

fooString = new Exporter().Export(foos.Select(x => new {TwiceTheHams = x.NumberOfHams * 2}),
                                          new List<ColumnDetails>
                                            {
                                              new ColumnDetails(x => x.TwiceTheHams, 12)
                                            });

【问题讨论】:

  • 我在提供的代码中看不到任何泛型的原因。
  • 当您谈论“匿名集合”和“匿名类型”时,我认为您真的不是指匿名类型 - 至少,您没有显示任何调用Export 使用匿名类型。如果你能给出一个失败的完整例子,那真的很有帮助......
  • @Tomas:这意味着您可以提供任何对象(例如业务实体)的 IEnumerable 并将其导出为一种报告。或 Linq 查询的输出。如果没有泛型,我看不到这样做的方法。
  • @Jon:第二个代码块使用匿名类型的集合调用 Export 方法(我的意思是匿名集合)。提供给它的 IEnumerable 使用 Select() 方法投影到匿名类型。
  • @David:啊,我将 Select 的调用误读为 导出之后。只显示匿名类型值的普通集合会更简单,例如new[] { new { X="x" }, new { X="y" }。同样,一个完整的例子会很有用。 (例如,当T 是匿名的时,你是如何创建List&lt;ColumnDetails&lt;T&gt;&gt; 的?)

标签: generics c#-3.0 type-inference


【解决方案1】:

这足以解决它吗?

导出

fooString = new Exporter().Export<Foo>(foos,
     new List<ColumnDetails<Foo>>
          {
               new ColumnDetails<Foo>(x => x.Name, 12),
               new ColumnDetails<Foo>(x => x.NumberOfHams, 4),
          });

【讨论】:

  • 该代码目前适用于已知类型,例如 Foo。它不适用于匿名类型的集合。
  • 我明白了。匿名类型可能更难,因为您必须使用推理。您可以随时切换到 Export 并让它在没有安全网的情况下飞行。
  • @Micheal 没有dynamic 也是可行的,尽管它有点难看。查看我的答案的最新编辑。
【解决方案2】:

这样的事情怎么样?

anonList 让你有一个引用 IEnumerable&lt;anontype&gt;CreateColumnDetails&lt;T&gt; 中的 T foo 让编译器推断 T 是什么类型,允许你使用匿名类型构造对象作为 T 的值

class Program
{
    public static ColumnDetails<T> CreateColumnDetails<T>(T foo, Func<T, object> func, int x)
    {
        return new ColumnDetails<T>(func, x);
    }
    static void Main(string[] args)
    {
        IEnumerable<Foo> foos = new List<Foo>();
        var anonList = foos.Select(x => new {TwiceTheHams = x.NumberOfHams*2});
        var fooString = new Exporter().Export(anonList,
                                      anonList.Select(y => CreateColumnDetails(y, z => z.TwiceTheHams, 12)));
    }
}
public class Exporter
{
    public string Export<T>(IEnumerable<T> enumerable, IEnumerable<ColumnDetails<T>> columnDetails)
    {
        return string.Empty;
    }
}

public class ColumnDetails<T>
{
    public ColumnDetails(Func<T, object> func, int x)
    {

    }
}
public class Foo
{
    public string Name { get; set; }
    public string NumberOfHams { get; set; }
}

【讨论】:

  • 我解释得很糟糕。我的意思是如果x 是匿名类型的集合,我不能调用Export&lt;T&gt;(IEnumerable&lt;T&gt; x, IEnumerable&lt;ColumnDetails&lt;T&gt;&gt; y),因为那样我就不能实例化ColumnDetails&lt;T&gt; 的集合。天哪,这东西太重了。
  • @David 你能展示一下 ColumnDetails 的样子吗?这可能会有所帮助。
  • 这行得通,但正如你所说,它有点难看。我认为基本上我最初的想法是正确的——泛型类型推断并没有走这么远。
【解决方案3】:

所以你想传递一个List&lt;ColumnDetails&lt; *anonymouse type with TwiceTheHams property* &gt;&gt;

在我看来,您需要一个通用辅助函数,该函数将采用 IEnumerable&lt;T&gt; 参数并从中构造一个 ColumnDetails 对象列表。然后插入对该函数的调用作为Export 的第二个参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多