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

时间:2018-01-20 18:36:37

标签: c# file oop

将所有行从文本文件保存到对象的正确方法是什么。我有像这样的.txt文件

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

从这个文件中我知道写入文件的每个数据的位置,并且所有数据都被格式化。

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

我创建了类数据,其中包含有关开始,结束位置,值,错误的信息。

然后我制作了包含Data类型列表的类Line,以及包含从某行创建的所有错误的列表。从行到对象加载数据后,数据I循环遍历lineError并从所有行添加错误,因为我需要将每行的错误保存到数据库。

我的问题是这种将数据从文件保存到对象的正确方法,以及在将相同数据保存到数据库之后,建议采用更好的方法吗?

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>();
}

1 个答案:

答案 0 :(得分:0)

我认为重点是使用OOP。我还假设解析是次要任务,我不会考虑其实现的选项。

首先,有必要确定主要作用对象。看起来很奇怪,这不是Book,而是字符串本身(例如DataLine)。最初,我想从字符串创建Book(通过单独的构造函数),但那将是一个错误。

哪些操作应该能够执行DataLine? - 事实上,只有一个 - process。我看到这个方法有两个可接受的选项:

  1. process返回Book 会引发异常。 (Book process()

  2. process不返回任何内容,但会与其他对象进行交互。 (void process(IResults result)

  3. 第一个选项有以下缺点:

    • 很难测试(虽然这适用于第二种选择)。所有验证都隐藏在DataLine内。

    • 返回一些错误是不可能/困难的。

    • 该计划旨在处理不正确的数据,因此通常会生成预期的例外情况。这违反了例外意识形态。此外,人们担心性能会下降。

    第二种选择没有最后两个缺点。 IResults可以包含方法error(...),以返回多个错误,以及success(Book book)

    通过添加process可以显着提高IValidator方法的可测试性。此对象可以作为参数传递给DataLine构造函数,但这并不完全正确。首先,这种不必要的记忆费用因为它不会给我们带来实实在在的好处。其次,这与DataLine类的本质不符。 DataLine仅表示可以以特定方式处理的行。因此,一个好的解决方案是void process (IValidator validator, IResults result)

    总结以上内容(可能包含语法错误):

    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
            }
        }
    }
    

    下一步是使用线条创建文件模型。这里有很多选择和细微差别,但我想关注IEnumerable<DataLine>。理想情况下,我们需要创建一个DataLines类,该类将支持IEnumerable<DataLine>并从文件或IEnumerable<string>加载。然而,这种方法相对复杂和冗余,仅在大型项目中才有意义。一个更简单的版本:

    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));
        }
    }
    

    你可以无限地改进代码,引入新的和新的抽象,但在这里你必须从常识和特定问题开始。

    P上。 S.对不起“奇怪的”英语。 Google并不总是正确地翻译这些复杂的主题。