Я пытаюсь читать данные из файла CSV по одной строке за раз. Первая строка, заголовки столбцов, определяет тип данных в каждой строке. Я уже знаю, что все данные принадлежат классу, который есть в моем проекте под названием UserModel, но я пытаюсь сделать это без жесткого кодирования данных в поля UserModel. Я могу прочитать первые пару строк и правильно создать первый экземпляр пользовательской модели. Но все разваливается, когда я пытаюсь прочитать третью строчку. Я использую словарь и пытаюсь использовать экземпляр созданного словаря, когда читаю первые пару строк. Смысл использовать порядок ключей в экземпляре Dictionary и просто обновлять значения следующим набором данных, но я не могу понять, почему набор данных просто не совпадает с нужными ключами.
Я получил здесь отличный код и использовал его. Метод DictionaryToObject() является одним из них. Я думаю, что использую больше циклов, чем нужно, и недостаточно знаю, чтобы использовать какой-либо другой способ доступа к некоторым структурам данных, таким как массив строк, список и словарь, который у меня есть. Я новичок и, возможно, использовал неправильную структуру данных или даже какой-то ненужный код, пытаясь получить желаемый результат.
public class MyData
{
BindingList<UserModel> users = new BindingList<UserModel>();
UserModel currentUser = new UserModel();
public BindingList<UserModel> GetUsers()
{
string[] lines = File.ReadAllLines("StandardDataSet.csv");
// Add error handing to make sure all lines have four enteris
foreach (string line in lines.Skip(1))
{
//I am not sure how to handle the first line that is a header
string [] values = line.Split(',').Select(x => x.Trim()).ToArray();
currentUser.FirstName = values[0];
currentUser.LastName = values[1];
int.TryParse(values[2], out int age);
currentUser.Age = age;
bool.TryParse(values[3], out bool alive);
currentUser.IsAlive = alive;
users.Add(currentUser);
}
return users;
}
private static T DictionaryToObject<T>(IDictionary<string, object> dict) where T : new()
{
T t = new T();
PropertyInfo[] properties = t.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
if (!dict.Any(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase)))
continue;
KeyValuePair<string, object> item = dict.First(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase));
Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
//if (item.Value is '0') Convert.ToBoolean(Convert.ToInt32(item.Value));
object newA = Convert.ChangeType(item.Value, newT);
t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
}
return t;
}
public BindingList<UserModel> GetUsersAdvanced()
{
users = new BindingList<UserModel>();
var dict= new Dictionary<string,object>();
string[] lines = File.ReadAllLines("AdvancedDataSet.csv");
var header = lines.First().Split(',');
var data = lines.Skip(1).First().Split(',');
for (int i = 0; i < header.Length; i++)
{
if (data[i] == "0" || data[i] == "1")
{
Boolean IsAlive = Extensions.ToBoolean(data[i]);
dict.Add(header[i], IsAlive);
}
else
//if (data[i]!= "0" || data[i]! = "1")
dict.Add(header[i], data[i]);
}
currentUser = DictionaryToObject<UserModel>(dict);
var dictCopy = new Dictionary<string, object>(dict);
var dictConcurrent = new ConcurrentDictionary<string, object>(dict);
foreach (var line in lines.Skip(1))
{
if (line != null) data = line.Split(',');
foreach (var key in dict.Keys)
{
int i = 0;
if (data[i] == "0" || data[i] == "1")
{
Boolean IsAlive = Extensions.ToBoolean(data[i]);
dictCopy[key] = IsAlive;
i++;
continue;
}
else
dictCopy[key] = data[i];
i++;
}
currentUser = DictionaryToObject<UserModel>(dictCopy);
users.Add(currentUser);
currentUser = new UserModel();
}
return users;
}
Я добавлю к припеву, использую библиотеку
Как говорится в комментариях людей, я также рекомендую использовать существующие библиотеки. Обычно они также поддерживают такие сопоставление данных с объектом и конверсия данных, которые вы делаете в своем коде. Итак, сначала попробуйте один или два.
Как насчет:
Кстати по порядку элементов в Dictionary можно прочитать причину здесь
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair structure representing a value and its key. The order in which the items are returned is undefined.
Итак, как насчет сохранения заголовков столбцов в списке? Таким образом, вы можете сохранить порядок. Код будет примерно таким, как показано ниже.
Но, пожалуйста, возьмите это как пример для заказанных товаров. Опять же, сначала попробуйте некоторые библиотеки, тогда вы увидите более интересные функции и получите более аккуратный код с ними.
public BindingList<UserModel> GetUsersAdvanced()
{
users = new BindingList<UserModel>();
string[] lines = File.ReadAllLines("AdvancedDataSet.csv");
var cols = lines.First().Split(',').ToList();
// validate column name duplication here!
foreach (var line in lines.Skip(1))
{
if (line != null) data = line.Split(',');
for (var i = 0; i < cols.Count(); i++)
{
var key = cols[i];
var dict = new Dictionary<string, object>();
if (data[i] == "0" || data[i] == "1")
{
Boolean IsAlive = Extensions.ToBoolean(data[i]);
dict.Add(key, IsAlive);
}
else
dict.Add(key, data[i]);
var currentUser = DictionaryToObject<UserModel>(dict);
users.Add(currentUser);
}
return users;
}
}
Спасибо большое. Я делал это, чтобы учиться, и надеялся, что кто-то откликнется.
Существует множество инструментов и библиотек, которые сделают все это за вас... и сделают это довольно хорошо.