开发者

C# generics: failure of generic type inference means I cannot use anonymous type

I have a class Exporter which has a generic method which accepts an IEnumerable<T> and creates an export document by enumerating its property values using reflection:

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

Because of generic type inference, I can supply this with an anonymous collection type. Note the absence of the generic parameter in the method call below:

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

We all love C#3. However, I would like to adapt this class so that I can enter more information about the columns in the export document, for example the width.

I have created a new method in the export class which looks like this:

public string Export<T>(IEnumerable<T> enumerable, IEnumerable<ColumnDetails<T>> columnDetails)
    {
      //Implem开发者_如何学编程entation omitted
    }

Ideally, the syntax would be like this, where foos is of type IEnumerable<Foo>:

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

However, when I call the new Export() overload as above, the generic type inference doesn't seem to be clever enough to infer that the generic parameter T for the ColumnDetails<T> should be the same as the generic parameter T for the IEnumerable. This means that I must specify List<ColumnDetails<Foo>> as the parameter, and therefore I cannot use this with anonymous collections.

I'm really new to generics and type inference. Is what I'm trying to do possible? Do I need to restructure the code somehow?

Edit: this is what I cannot do, because Visual Studio needs the generic parameter for ColumnDetails, which I don't have:

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


Would this be sufficient to fix it?

Export<Foo>

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


How about something like this?

The anonList lets you have a reference IEnumerable<anontype> and the T foo in CreateColumnDetails<T> lets the compiler infer what type T is, allowing you to construct the object with an anonymous type as the value of 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; }
}


So you want to pass in a List<ColumnDetails< *anonymouse type with TwiceTheHams property* >> ?

It looks to me like you need a generic helper function that will take an IEnumerable<T> parameter and construct a list of ColumnDetails objects from it. Then insert a call to that function as the second parameter to Export.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜