WedX - журнал о программировании и компьютерных науках

CsvHelper для сохранения объекта производного класса из абстрактного класса

[Serializable]
public abstract class AbstractModel : ObservableObject
{
    // nothing.
}

public class RealModel : AbstractModel 
{
    public string PropertyA {get; set;}
    public string PropertyB {get; set;}
}

Обратите внимание, что ObservableObject принадлежит Mvvm-light.

С приведенными выше моделями я использовал CsvHelper, как показано ниже.

AbstractModel instance = new RealModel()
                             {
                                 PropertyA = "foo",
                                 PropertyA = "bar"
                             };

using (TextWriter file = new StreamWriter("path"))
using (var csv = new CsvWriter(file))
{
    csv.WriteRecord(instance);
}

Выдает ошибку, как показано ниже;

Никакие свойства не сопоставлены для типа «AbstractModel».

Он отлично работает, когда я вместо этого устанавливаю RealModel instance = new RealModel();. Но у меня есть различные производные классы, и я хочу сохранить их в одном методе Save.

Как я могу сделать?

05.01.2016

Ответы:


1

Я знаю, что этому уже три года, но я пытался сделать то же самое и нашел хак, чтобы заставить его работать.

Код нарушения в csvHelper следующий:

public virtual Type GetTypeForRecord<T>(T record)
{
    var type = typeof(T);
    if (type == typeof(object))
    {
        type = record.GetType();
    }

    return type;
}

Универсальный C#, который передается этому методу, определяется во время компиляции, поэтому T всегда будет базовым классом, а не производным классом, но если вы приведете к типу object перед вызовом WriteRecord, метод будет использовать GetType(), который вернет производный тип.

AbstractModel instance = new RealModel()
                             {
                                 PropertyA = "foo",
                                 PropertyA = "bar"
                             };

using (TextWriter file = new StreamWriter("path"))
using (var csv = new CsvWriter(file))
{
    csv.WriteRecord((object)instance);
}
20.02.2019

2

К сожалению, я бы сказал, что так и должно быть. На выходе получается не файл XML, а файл CSV. И файл CSV имеет только один заголовок (если он есть; не все файлы CSV имеют заголовок).

Парсер не может определить класс по данным в строке.

Пример стандартных данных CSV 1 (имена):

ID,GivenName,FamilyName
1,John,A
2,Mike,B

Стандартные данные CSV, пример 2 ("годовщины"):

Date,Anniversary
1.1.,New year

При сохранении в файл CSV у вас не может быть двух «строк заголовка»; как синтаксический анализатор должен знать, в какой дочерний класс декодировать вывод? Имена или юбилеи? Почему первая строка "имя", а вторая "годовщина"? Почему нельзя по-другому?

Этот подход не является хорошим. По крайней мере, не для файла CSV. Всегда должна быть таблица с точным количеством столбцов для каждой строки. Когда количество данных всегда точное, вы можете использовать конвертеры из вашего класса в универсальный класс и из универсального класса в определенные классы данных (для парсера).

Пример нестандартных данных: (имена и годовщины; без строки заголовка):

1,John,A
1.1.,New year
2,Mike,B

Попробуйте спросить себя, как парсер должен обрабатывать этот файл? Да, данные хранятся "в формате CSV", но я не думаю, что эти данные верны. Это не так, как должно быть.

Я знаю, что есть ситуации, когда вам нужно использовать этот подход (форматированные данные, первый элемент указывает тип, все остальные значения в строке являются данными для данного типа). Но для этого использования вам нужно использовать другой подход к хранению и анализу данных.

Пример другого подхода:

public abstract class AbstractModel : ObservableObject
{
    // no property

    protected string Prefix(object data)
    {
       if (ReferenceEquals(data, null))
         return string.Empty;
       string result = data.ToString();
       if (data.Contains(",") || data.Contains("\""))
         return $"\"{data}\"";
       return data;
    }

}

public class RealModel : AbstractModel 
{
    public string PropertyA {get; set;}
    public string PropertyB {get; set;}

    public override string ToString()
    {
       return $"{Prefix(PropertyA)},{Prefix(PropertyB)}";
    }
}

И сохранить с помощью:

using (StreamWriter file = new StreamWriter("path"))
{
  foreach (AbstractModel instance in allInstances)
    file.WriteLine(instance);
}
05.01.2016
  • Но я намеревался сохранить один объект в один файл, поэтому заголовок не меняется. может это по дизайну? 05.01.2016
  • понятно. Я вижу, что вы говорите. 05.01.2016
  • Новые материалы

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..


    Для любых предложений по сайту: [email protected]