简体   繁体   English

将数据从文件保存到对象C#的正确方法是什么

[英]What is proper way to save data from file to object C#

what is proper way to save all lines from text file to objects. 将所有行从文本文件保存到对象的正确方法是什么? I have .txt file something like this 我有这样的.txt文件

0001Marcus Aurelius          20021122160   21311
0002William  Shakespeare     19940822332   11092
0003Albert Camus             20010715180   01232

From this file I know position of each data that is written in file, and all data are formatted. 从这个文件中,我知道写入文件的每个数据的位置,并且所有数据都已格式化。

Line number is from 0 to 3
Book author is from 4 to 30
Publish date is from 31 to 37
Page num. is from 38 to 43
Book code is from 44 to 49

I made class Data which holds information about start, end position, value, error. 我制作了数据类,其中包含有关开始,结束位置,值,错误的信息。

Then I made class Line that holds list of type Data, and list that holds all error founded from some line. 然后,我创建了Line类,该类保存Data类型的列表,并保存所有从某行创建的错误的列表。 After load data from line to object Data I loop through lineError and add errors from all line to list, because I need to save errors from each line to database. 从行到对象数据加载数据后,我通过lineError循环并从所有行到列表添加错误,因为我需要将每行的错误保存到数据库。

My question is this proper way to save data from file to object and after processing same data saving to database, advice for some better approach? 我的问题是这种将数据从文件保存到对象的正确方法,并且在将相同的数据保存到数据库后进行处理,请教一些更好的方法吗?

public class Data
{
    public int startPosition = 0;
    public int endPosition = 0;
    public object value = null;
    public string fieldName = "";
    public Error error = null;

    public Data(int start, int end, string name)
    {
        this.startPosition = start;
        this.endPosition = end;
        this.fieldName = name;
    }

    public void SetValueFromLine(string line)
    {
        string valueFromLine = line.Substring(this.startPosition, this.endPosition - this.startPosition);
        // if else statment that checks validity of data (lenght, empty value) 
        this.value = valueFromLine;
    }

}

public class Line
{
    public List<Data> lineData = new List<Data>();
    public List<Error> lineError = new List<Error>();

    public Line()
    {
        AddObjectDataToList();
    }

    public void AddObjectDataToList()
    {
        lineData.Add(new Data(0, 3, "lineNumber"));
        lineData.Add(new Data(4, 30, "bookAuthor"));
        lineData.Add(new Data(31, 37, "publishData"));
        lineData.Add(new Data(38, 43, "pageNumber"));
        lineData.Add(new Data(44, 49, "bookCode"));
    }

    public void LoadLineDataToObjects(string line)
    {
        foreach(Data s in lineData)
        {
            s.SetValueFromLine(line);
        }
    }

    public void GetAllErrorFromData()
    {
        foreach (Data s in lineData)
        {
            if(s.error != null)
            {
                lineError.Add(s.error);
            }

        }
    }

}


public class File
{
    public string fileName;
    public List<Line> lines = new List<Line>();
}

I assume that the focus is on using OOP. 我假设重点是使用OOP。 I also assume that parsing is a secondary task and I will not consider options for its implementation. 我还假定解析是次要任务,并且我将不考虑其实现的选项。

First of all, it is necessary to determine the main acting object. 首先,有必要确定主要作用对象。 Strange as it may seem, this is not a Book , but the string itself (eg DataLine ). 看起来很奇怪,这不是Book ,而是字符串本身(例如DataLine )。 Initially, I wanted to create a Book from a string (through a separate constructor), but that would be a mistake. 最初,我想通过一个字符串(通过单独的构造函数)创建一Book ,但这是一个错误。

What actions should be able to perform DataLine ? 什么动作应该能够执行DataLine - In fact, only one - process . -实际上只有一个process I see two acceptable options for this method: 我看到此方法有两个可接受的选项:

  1. process returns Book or throws exceptions. process返回Book 引发异常。 ( Book process() ) Book process()

  2. process returns nothing, but interacts with another object. process什么也不返回,但是与另一个对象进行交互。 ( void process(IResults result) ) void process(IResults result)

The first option has the following drawbacks: 第一种选择具有以下缺点:

  • It is difficult to test (although this applies to the second option). 很难测试(尽管这适用于第二个选项)。 All validation is hidden inside DataLine . 所有验证都隐藏在DataLine

  • It is impossible/difficult to return a few errors. 返回一些错误是不可能/困难的。

  • The program is aimed at working with incorrect data, so expected exceptions are often generated. 该程序旨在处理不正确的数据,因此通常会生成预期的异常。 This violates the ideology of exceptions. 这违反了例外意识形态。 Also, there are small fears of slowing performance. 同样,人们很少担心性能会降低。

The second option is devoid of the last two drawbacks. 第二种选择没有最后两个缺点。 IResults can contain methods error(...) , to return several errors, and success(Book book) . IResults可以包含方法error(...) ,返回多个错误和success(Book book)

The testability of the process method can be significantly improved by adding IValidator . 所述的可测试性process的方法可以通过添加能够改善显著IValidator This object can be passed as a parameter to the DataLine constructor, but this is not entirely correct. 可以将此对象作为参数传递给DataLine构造函数,但这并不完全正确。 First, this unnecessary expense of memory because it will not give us tangible benefits. 首先,这种不必要的内存开销是因为它不会给我们带来明显的好处。 Secondly, this does not correspond to the essence of the DataLine class. 其次,这与DataLine类的本质不符。 DataLine represents only a line that can be processed in one particular way. DataLine仅代表可以以一种特定方式处理的线。 Thus, a good solution is the void process (IValidator validator, IResults result) . 因此,一个好的解决方案是void process (IValidator validator, IResults result)

Summarize the above (may contain syntax errors): 总结以上内容(可能包含语法错误):

interface IResults {
    void error (string message);
    void success (Book book);
}

interface IValidator {
    // just example
    bool checkBookCode (string bookCode);
}

class DataLine {
    private readonly string _rawData;
    // constructor
    /////////////////
    public void process (IValidator validator, IResults result) {
        // parse _rawData
        bool isValid = true; // just example! maybe better to add IResults.hasErrors ()
        if (! validator.checkBookCode (bookCode)) {
            result.error("Bad book code");
            isValid = false;
        }

        if (isValid) {
            result.success(new Book (...));
            // or even result.success (...); to avoid cohesion (coupling?) with the Book
        }
    }
}

The next step is to create a model of the file with the lines. 下一步是使用这些行创建文件模型。 Here again there are many options and nuances, but I would like to pay attention to IEnumerable<DataLine> . 同样,这里有很多选项和细微差别,但我要注意IEnumerable<DataLine> Ideally, we need to create a DataLines class that will support IEnumerable<DataLine> and load from a file or from IEnumerable<string> . 理想情况下,我们需要创建一个支持IEnumerable<DataLine>DataLines类,并从文件或IEnumerable<string>加载。 However, this approach is relatively complex and redundant, it makes sense only in large projects. 但是,这种方法相对复杂且多余,仅在大型项目中才有意义。 A much simpler version: 一个简单得多的版本:

interface DataLinesProvider {
    IEnumerable <DataLine> Lines ();
}

class DataLinesFile implements DataLinesProvider {
    private readonly string _fileName;
    // constructor
    ////////////////////
    IEnumerable <DataLine> Lines () {
        // not sure that it's right
        return File
            . ReadAllLines (_fileName)
            .Select (x => new DataLine (x));
    }
}

You can infinitely improve the code, introduce new and new abstractions, but here you must start from common sense and a specific problem. 您可以无限地改进代码,引入新的和新的抽象,但是这里您必须从常识和特定问题开始。

PS sorry for "strange" English. PS对不起,“奇怪”的英语。 Google not always correctly translate such complex topics. Google并不总是正确翻译此类复杂的主题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM