Я пытаюсь преобразовать свой объект, который имеет только 1 элемент (IList класса), этот класс содержит 6 свойств - 4 строки, 1 IList другого класса и 1 IList строки. Я использую ниже общий метод для преобразования: -
public static DataTable ToDataTable<T>(IList<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Defining type of data column gives proper data table
var type = (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType);
//Setting column names as Property names
dataTable.Columns.Add(prop.Name, type);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
}
На данный момент - dataTable.Rows.Add(values); У меня есть значения списка для свойств 4 и 5, но когда я добавляю их в строку, в строке отображается текст (тип свойства). Хотя мне нужно, чтобы каждый элемент из 4 и 5 свойств попадал в следующую строку. Например :-
values[0] - "FirstString",
values[1] - "SecondString",
values[2] - "ThirdString",
values[3] - "FourthString",
values[4] - Count 2 - 100, 200 (IList<AnotherClass>()),
values [5] - Count 2 - "10W", "20W" (IList<string>)
Я хочу ниже типа вывода: -
1String | 2String | 3String | 4String | Per | W |
:-----------|:------------:|:-----------:|:------------:|:---:|---:|
FirstString | SecondString | ThirdString | FourthString | 100 | 10W|
FirstString | SecondString | ThirdString | FourthString | 200 | 20W|
В то время как результат, который я сейчас получаю: -
1String | 2String | 3String | 4String | Per | W |
:-----------|:------------:|:-----------:|:------------:|:--------------:|--------------:|
FirstString | SecondString | ThirdString | FourthString | typeofproperty | typeofproperty|
Я просто хочу, чтобы список моих объектов преобразовывался в DataTable.
Ниже приведен результат отладки в соответствии с приведенным ниже решением: -
@Dennis, все еще получаю тип свойства как значение для свойства типа списка.
Вызов этого метода — toDataTable<anotherClass>(IList<anotherClass>). Как я могу сгладить объект?
Звонящий должен это сделать. Иначе это будет не банально. Другой вариант — ввести ограничения для структуры T
(например, только 2 списка, длина списков одинаковая), но в этом случае конвертер общего назначения не имеет смысла.
Ваш код отлично работает для T
, который содержит только скалярные свойства (то есть примитивные типы, строки, даты и т. д.).
Когда он имеет дело с коллекцией или вложенным объектом, он пытается сохранить этот объект или коллекцию в строке таблицы данных как есть, поэтому результат не такой, как вы ожидали.
Чтобы получить желаемый результат, вам нужно сначала сгладить элементы списка.
Поскольку T
может быть чем угодно, логика сглаживания не может быть реализована в общем виде. Но вызывающий может сделать это за вас, так как он знает все о структуре объекта.
Наличие таких типов:
class Foo
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
public IList<Bar> Bars { get; set; }
public IList<string> Strings { get; set; }
}
class Bar
{
public int A { get; set; }
}
вы можете написать этот код:
var items = new List<Foo>
{
new Foo
{
A = "FirstString",
B = "SecondString",
C = "ThirdString",
D = "FourthString",
Bars = new List<Bar>
{
new Bar { A = 100 },
new Bar { A = 200 }
},
Strings = new List<string>
{
"10W",
"20W"
}
}
};
var dataTable = items
.SelectMany(item => item.Bars.Zip(item.Strings, (bar, stringValue) => new
{
BarA = bar.A,
StringValue = stringValue
}),
(item, _) => new
{
item.A,
item.B,
item.C,
item.D,
_.BarA,
_.StringValue
})
.ToDataTable();
Результат:
Как видите, логика сглаживания внутри SelectMany
зависит от того, что такое T
. Если будет, скажем, 3 вложенных списка и Bar
будет содержать свойство public Boo { get; set; }
, эта логика изменится, чтобы отразить новую структуру объекта.
P.S. Я немного изменил определение ToDataTable
, чтобы сделать его методом расширения для IEnumerable<T>
:
static class ConversionExtensions
{
public static DataTable ToDataTable<T>(this IEnumerable<T> items)
{
// your code here
}
}
Привет, что такое item.Strings и stringValue в примере? item.Bars.Zip(item.Strings, (bar, stringValue) => new { BarA = bar.A, StringValue = stringValue })
item.Strings
является IList<string>
свойством Foo
класса. stringValue
является элементом item.Strings
. Я думаю, вы спрашиваете в основном о методе Zip
- он просто делает из двух последовательностей разных типов третью. Буквально составляет последовательность пар (100, "10W"), (200, "20W").
Да, это работает, но после определения элементов я не могу вызвать метод ToDataTable(). Просят меня определить тип. Вы имеете какое-нибудь представление об этом?
@EktaC, ну, я не знаю, как выглядит твой модифицированный код. :) Если вы можете опубликовать или поделиться им, пожалуйста, сделайте это.
Пожалуйста, посмотрите на приведенный ниже скриншот, предоставленный мной.
Определите ToDataTable
как метод расширения. Смотрите это: learn.microsoft.com/en-us/dotnet/csharp/programming-guide/…
Обновлен ответ, чтобы показать, как определить метод расширения, см. класс ConversionExtensions
.
Не могли бы вы поделиться своим методом ToDataTable(), который вы использовали для показанного вывода, пожалуйста? @Деннис
@EktaC, на самом деле, это твой код из исходного поста. :) Я только что скопировал/вставил без изменений. Источник: dotnetfiddle.net/1J5O1H
Убедитесь, что значение снимка экрана не исходит из свойств типа списка. Но количество строк увеличилось в соответствии с количеством элементов.
@EktaC, вы передаете item.ToString()
в качестве второй последовательности в метод Zip
. Следовательно, вы «запаковываете» каждый элемент Per_100
с каждым символом в имени типа SmallType
. Я сомневаюсь, что это то, что вы хотите.
Сначала вам нужно сгладить ваши объекты, чтобы ваш код заработал. Это будет непросто сделать в общем виде, потому что T может быть чем угодно, так что логика сглаживается. Было бы намного проще, если бы
items
был готов к конвертации DTO только со скалярными свойствами (я имею в виду без коллекций или других вложенных объектов).