Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从抽象类访问泛型列表_C#_Generics - Fatal编程技术网

C# 从抽象类访问泛型列表

C# 从抽象类访问泛型列表,c#,generics,C#,Generics,出于学习目的,我正在尝试用C#创建自己的简单数据库。我已经编写了存储和加载表(类“Pizzas”)的代码。很简单,因为逻辑是硬编码的——它只支持“Pizzas”类型的实例。 不,我想概括我的数据库逻辑。这是我迄今为止所做的(简化): 请注意:我有一个抽象类的唯一原因是因为在MyDB类中,我无法键入 List<MyTable<T>> _tables; List\u表; 是否有更好的方法将我的表保存在列表中?而是一个接口 公共类MyDB { 公共列表表; 公共MyDB()

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

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

List<MyTable<T>> _tables;
List\u表;
是否有更好的方法将我的表保存在列表中?而是一个接口

公共类MyDB
{
公共列表表;
公共MyDB(){u tables=new List();}
公共void AddTable(MyTable){_tables.Add(table);}
}
公共抽象类MyTable
{
受保护的MyTableDefinition\u tableDefinition;
公共摘要无效保存();
}
类MyTable:MyTable
{
公共列表行;
公共MyTable()
{
_行=新列表();
_tableDefinition=新的MyTableDefinition(typeof(T));
}
内部void AddRecord(T record){u rows.Add(record);}
内部空洞清除器记录(T记录){u行。清除(记录);}
public override void Save(){Debug.WriteLine(“正在进行的工作…”);}
}
公共类MyTableDefinition{/*bla*/}
这实际上是我想要的。现在,我的问题是我的类,它应该处理磁盘的读写。我想把它分开可能是个好主意,这样我就可以处理不同的平台(常规文件、隔离存储、存储文件等)

公共静态类MyIOforFile
{
列表流;
公共静态测试(MyDB数据库)
{
字符串tmpPath=@“C:\tmp”;
foreach(数据库中的var表。\u表)
{
使用(var file=newbinarywriter(file.Open(tmpPath+@“\SampleOutput.txt”,FileMode.Create)))
{
//问题:无法访问此处的_行。
foreach(表中的var项。\u行)
{
// ...
}
}
}
}
}
注意:在我的例子中,反射是访问_行的唯一方法吗?在OOP中有没有合适的方法来处理我的场景(不太喜欢反射)

这是我如何称呼代码的:

var testdb=new MyDB();
var PizzaTable=新的MyTable();
testdb.AddTable(PizzaTable);
MyIOLayer.Test(testdb);

谢谢你看

您遇到了一个困难的问题:您有一个未知泛型类型的泛型集合,并且希望在不访问该泛型类型的情况下处理它

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

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

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

这是我将使用的解决方案。首先,与抽象类相比,更喜欢接口,尤其是在共享逻辑很少的情况下。其次,在接口中定义通用逻辑(迭代时所做的事情)。最后,保持字段的私有性,并创建与字段交互的适当方法(参见下面的示例
ForEachRow

这些是接口:

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

public interface IRow
{
    void Print();
}
公共接口ITable
{
MyTableDefinition TableDef{get;}
作废打印();
无效ForEachRow(动作);
}
公共接口IRow
{
作废打印();
}
以下是如何使用它们的示例:

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() { ... }
}
公共类MyTable:ITable其中T:IRow
{
私有列表行;
私有MyTableDefinition_tableDef;
公共MyTable(){…}
公共MyTableDefinition TableDef{get{return}
public void Print(){ForEachRow(row=>row.Print());}
公共无效ForEachRow(操作)
{
foreach(T行在_行中)
{
行动(世界其他地区);
}
}
}
公共类MyRow:IRow
{
你想要什么就有什么;
public void Print(){…}
}

@lukegravitt:这不是唯一的问题。@SLaks是的,它也需要是抽象类的成员,而不是泛型类的成员,但它是泛型的,因此需要重新设计。您打算如何使用
?这将有助于指导您键入
MyTable
应该是。@TimS。我想将表中的行写入磁盘上的自定义二进制格式(考虑一个简单的数据库)。将表写入磁盘的逻辑应该是相同的。唯一的区别是列的集合不同。仅供参考:在MyTableDefinition中,我使用特定表的数据类型、长度存储列。@lukegravitt是的,你是对的。我的源代码要复杂得多,我只提取了所需的位。但正如你所知,这不是我的专业问题。这看起来是一个优雅的解决方案。我不明白的是,如果我想将MyRow的数据写入磁盘,我需要能够访问ForEachRow()中的_whateverFieldsYouWant。我知道MyTableDefinition中所有字段的名称(作为字符串)和类型(作为字符串)(我使用反射在公共MyTable()中获取此信息).但我不知道如何使用这些信息将我的代码概括为所有可能的IRow类型。正在实现自定义打印()对于IRow的每个实现,唯一的方法是什么?如果你想要某种动态的、通用的
类,你应该用那种方法来实现。这可以通过扩展
动态对象
或者用你自己的实现来实现。如果每个类都有多个实现了
IRow
的类,并且有一些自定义行为,但是仍然有一些c契约填充(
Print()
SaveToDisk()
,等等),然后在每一个上实现接口可能是最有意义的。使
MyRow
也成为泛型,并将行行为封装到单个类中也是有意义的(因此,您不需要
IRow
接口,但可能需要一些数据类型)。
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() { ... }
}