C# generics: ошибка вывода универсального типа означает, что я не могу использовать анонимный тип
У меня есть класс 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. Тем не менее, я хотел бы адаптировать этот класс, чтобы я мог ввести дополнительную информацию о Столбцах в экспорте документ, например ширина.
Я создал новый метод в классе export, который выглядит следующим образом:
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>> в качестве параметра, и поэтому я не могу использовать его с анонимными коллекциями.Я действительно Новичок в генериках и выводе типов. Возможно ли то, что я пытаюсь сделать? Нужно ли как-то реструктурировать код?
Edit: это то, что я не могу сделать, потому что 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 ответов:
Как насчет чего-то вроде этого?
anonListпозволяет иметь ссылкуIEnumerable<anontype>, аT fooвCreateColumnDetails<T>позволяет компилятору определить тип T, что позволяет построить объект с анонимным типом в качестве значенияTclass 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; } }
Будет ли этого достаточно, чтобы исправить это?
Экспорт
fooString = new Exporter().Export<Foo>(foos, new List<ColumnDetails<Foo>> { new ColumnDetails<Foo>(x => x.Name, 12), new ColumnDetails<Foo>(x => x.NumberOfHams, 4), });
Итак, вы хотите пройти в
List<ColumnDetails< *anonymouse type with TwiceTheHams property* >>?Мне кажется, что вам нужна универсальная вспомогательная функция, которая возьмет параметр
IEnumerable<T>и построит из него список объектовColumnDetails. Затем вставьте вызов этой функции в качестве второго параметра вExport.
Comments