3

出于学习目的,我正在尝试用 C# 制作自己的简单数据库。我已经编写了代码来存储和加载一个表(类“披萨”)。很简单,因为逻辑是硬编码的——它只支持“Pizzas”类型的实例。不,我想概括我的数据库逻辑。这是我到目前为止所做的(简化):

请注意:我有一个抽象类的唯一原因是因为在 MyDB 类中,我无法输入

List<MyTable<T>> _tables;

有没有更好的方法将我的表格保存在列表中?一个接口代替?

public class MyDB
{
    public List<MyTable> _tables;
    public MyDB() {_tables = new List<MyTable>();}
    public void AddTable(MyTable table) {_tables.Add(table);}
}
public abstract class MyTable
{
    protected MyTableDefinition _tableDefinition;
    public abstract void Save();
}
class MyTable<T> : MyTable
{
    public List<T> _rows;
    public MyTable()
    {
        _rows = new List<T>();
        _tableDefinition = new MyTableDefinition(typeof(T));
    }

    internal void AddRecord(T record) {_rows.Add(record);}
    internal void RemoveRecord(T record) {_rows.Remove(record);}

    public override void Save() {Debug.WriteLine("Work in Progress...");}
}
public class MyTableDefinition { /* bla bla */ }

这实际上按我的意图工作。现在,我的问题是我的班级应该处理磁盘的读写。我认为将它分开可能是个好主意,这样我就可以处理不同的平台(常规文件、独立存储、存储文件等)。

public static class MyIOforFile
{
    List<Stream> _tableStreams;
    public static Test(MyDB database)
    {
        string tmpPath = @"C:\tmp";
        foreach (var table in database._tables)
        {
            using (var file = new BinaryWriter(File.Open(tmpPath + @"\SampleOutput.txt", FileMode.Create)))
            {
                // Problem: Can't access _rows here.
                foreach (var item in table._rows)
                {
                    // ...
                }
            }
        }
    }
}

注意:在我的情况下,反射是访问 _rows 的唯一方法吗?在 OOP 中是否有合适的方法来处理我的场景(不是反射的忠实粉丝)?

这就是我调用代码的方式:

var testdb = new MyDB();
var PizzaTable = new MyTable<PizzaItem>();
testdb.AddTable(PizzaTable);
MyIOLayer.Test(testdb);

感谢您的关注!

4

2 回答 2

1

您遇到了一个难题:您有一个未知泛型类型的泛型集合,并且您想在不访问该泛型类型的情况下对其进行处理。

您可以通过使用协方差公开基本类型的集合来解决此问题:

public abstract class MyTable {
    public abstract IEnumerable<object> UntypedRows { get; }
}

public class MyTable<T> : MyTable {
    public override IEnumerable<object> UntypedRows { get { return _rows; } }
}

如果您的所有行都有一个共同的基本类型,您可以限制T继承该类型,然后更改object为该类型。

显然,除非您知道类型参数是什么,否则您将无法访问不属于公共类型的任何内容。


或者,您可以将工作移至泛型类:

public abstract class MyTable {
    public abstract void SaveRows(...);
}

public class MyTable<T> : MyTable {
    public abstract void SaveRows(...) {
        // Write code here, with access to the generic type parameter
    }
}
于 2013-11-12T17:53:36.940 回答
1

这是我要使用的解决方案。首先,优先选择接口而不是抽象类,尤其是在共享逻辑很少的情况下。其次,在界面中定义您的通用逻辑(迭代时所做的事情)。最后,保持您的字段私有并创建适当的方法来与它们交互(参见ForEachRow下面的示例:

这些是接口:

public interface ITable
{
    MyTableDefinition TableDef { get; }
    void Print();
    void ForEachRow(Action<IRow> action);
}

public interface IRow
{
    void Print();
}

这些是如何使用它们的示例:

public class MyTable<T> : ITable where T : IRow
{
    private List<T> _rows;
    private MyTableDefinition _tableDef;

    public MyTable() { ... }
    public MyTableDefinition TableDef { get { return _tableDef; } }
    public void Print() { ForEachRow(row => row.Print()); }

    public void ForEachRow(Action<IRow> action)
    {
        foreach (T row in _rows)
        {
            action(row);
        }
    }
}

public class MyRow : IRow
{
    private int _whateverFieldsYouWant;
    public void Print() { ... }
}
于 2013-11-13T17:20:07.997 回答