C # generics: ошибка вывода обобщенного типа означает, что я не могу использовать анонимный тип - PullRequest
2 голосов
/ 28 мая 2011

У меня есть класс 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<Foo>:

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

Однако, когда я вызываю новую перегрузку Export(), как указано выше, вывод универсального типа не кажется достаточно умным, чтобы сделать вывод, что универсальный параметр T для ColumnDetails<T> долженбыть таким же, как универсальный параметр T для IEnumerable.Это означает, что я должен указать List<ColumnDetails<Foo>> в качестве параметра, и поэтому я не могу использовать это с анонимными коллекциями.

Я действительно новичок в обобщениях и выводе типов.Возможно ли то, что я пытаюсь сделать?Нужно ли как-то реструктурировать код?

Редактировать: это то, что я не могу сделать, потому что Visual Studio нужен универсальный параметр для ColumnDetails, которого у меня нет:

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

Ответы [ 3 ]

1 голос
/ 28 мая 2011

Этого будет достаточно, чтобы это исправить?

Экспорт

fooString = new Exporter().Export<Foo>(foos,
     new List<ColumnDetails<Foo>>
          {
               new ColumnDetails<Foo>(x => x.Name, 12),
               new ColumnDetails<Foo>(x => x.NumberOfHams, 4),
          });
0 голосов
/ 28 мая 2011

Как насчет чего-то подобного?

anonList позволяет вам иметь ссылку IEnumerable<anontype>, а T foo в CreateColumnDetails<T> позволяет компилятору определить тип 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; }
}
0 голосов
/ 28 мая 2011

То есть вы хотите передать List<ColumnDetails< *anonymouse type with TwiceTheHams property* >>?

Мне кажется, вам нужна общая вспомогательная функция, которая будет принимать параметр IEnumerable<T> и создавать из него список ColumnDetails объектов. Затем вставьте вызов этой функции в качестве второго параметра в Export.

...