出于学习目的,我试图在C#中创建自己的简单数据库。我已经编写了代码来存储和加载表(Class“Pizzas”)。很简单,因为逻辑是硬编码的 - 它只支持“Pizzas”类型的实例。 不,我想概括我的数据库逻辑。这就是我到目前为止所做的(简化):
请注意:我有一个Abstract类的唯一原因是因为在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 */ }
这实际上和我的意图一样。现在,我的问题是我的类应该处理从磁盘读取和写入。我认为将它分开是一个好主意,这样我就可以处理不同的平台(常规文件,IsolatedStorage,Storagefile等)。
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)
{
// ...
}
}
}
}
}
注意:在我的情况下,Reflection是访问_rows的唯一方法吗?在OOP中是否有适当的方法来处理我的场景(不是反射的忠实粉丝)?
这就是我调用代码的方式:
var testdb = new MyDB();
var PizzaTable = new MyTable<PizzaItem>();
testdb.AddTable(PizzaTable);
MyIOLayer.Test(testdb);
感谢您一看!
答案 0 :(得分: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
}
}
答案 1 :(得分: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() { ... }
}