我该如何实现表格?

时间:2012-02-17 21:26:01

标签: c# .net oop

假设您需要将一些值存储在由多个列(例如关系数据库)组成的表中:例如,第一列为int,第二列为stringDateTime为第三个等等。

如果一个或多个列类似于主键,那么我们可以使用IDictionary,其Key将是充当主键的字段集。其余字段代表Value。在这种情况下,我可以创建一个或两个类/结构。例如,如果主键只是一个现有类型,我们只需要创建一个类/结构,如下所示:

public class MyValue
{
    public int Field1;
    public double Field2;
    public string Field3;
}

字典可以是Dictionary<int, MyValue>,而表格可以是以下内容。

public class MyTable
{
    private Dictionary<int, MyValue> _table;
    ...
}

显然,根据应用领域,上述字段可能存在范围和/或有效性规则:例如,Field1可能必须为正,依此类推......

作为第一种选择,我可以设计MyValue类,以便它引发一些例外以识别“违反规则”。但也许这种方法可能过多,尤其是如果类MyValue仅在MyTable内部使用:在这种情况下,我会编写如下代码并在MyTable类中处理有效性错误:也就是说,MyTable类在将数据字段插入字典之前检查数据字段,因此MyValue将是一个“愚蠢”的类......

namespace MyNamespace
{
    class MyValue
    {
        // only public fields
    }

    public class MyTable
    {
        private Dictionary<int, MyValue> _table;
        ...

        public void Add(int key, int field1, double field2, string field3)
        {
            // some code to check validity range for fields
            ...
        }
    }
}

此解决方案是否正确?或者我应该避免这种方法?我是否应该始终以完整的方式定义类/结构(异常处理,EqualsGetHashCode方法?

2 个答案:

答案 0 :(得分:4)

你所做的事情看起来过于复杂,脆弱,最终会导致可维护性的噩梦。

我说你有两种选择。

选项一:使用DataTable。它不必由实际数据库支持,您可以在运行时定义它的布局(包括列定义)。

选项二:定义一个实现“记录”逻辑的类。定义一个Collection来保存该类。使用LINQ“查询”集合,无论您需要什么。

两个选项之间的主要区别在于DataTable在您可以使用的规则类型方面非常有限。选项2,OTOH,可以让你精确地构建你想要的东西。

答案 1 :(得分:2)

我会让值自己检查它们的一致性。如果将字段实现为属性,则setter可以执行检查并抛出异常,例如,值超出范围。

我也建议采用一种更灵活的方法。定义表记录必须实现的接口

public interface IRecord<PK>
{
    PK ID { get; }
}

记录必须具有ID,该ID将用作主键。我们使用通用主键类型PK

现在你可以像这样定义一个值类

public class MyValue : IRecord<int>
{
    private int _field1;
    public int Field1
    {
        get { return _field1; }
        set
        {
            if (value < 0 || value > 1000) {
                throw new ArgumentException("Value of 'Field1' must be between 0 and 1000");
            }
            _field1 = value;
        }
    }

    public double Field2;

    #region IRecord<int> Members

    public int ID { get { return Field1; } }

    #endregion
}

如您所见,它实现了IRecord<int>并将Field1作为ID返回。 Field1检查传递给它的值。如果主键由多个字段组成,则可以使用类似Tuple(.NET 4.0)的类型作为主键类型。与IRecord<Tuple<int,double>>一样。

现在您可以定义通用表

public class Table<T, PK>
    where T : IRecord<PK>
{
    private Dictionary<PK, T> _table = new Dictionary<PK, T>();

    public void Add(T item)
    {
        _table.Add(item.ID, item);
    }
}

您可以像这样定义特定的表

public class MyTable : Table<MyValue, int>
{
}

更新:

或者,您可以让记录实现显式错误处理

public interface IRecord<PK> {
    PK ID { get; }

    bool IsValid { get; }
    string[] Errors { get; }
}