假设您需要将一些值存储在由多个列(例如关系数据库)组成的表中:例如,第一列为int
,第二列为string
, DateTime
为第三个等等。
如果一个或多个列类似于主键,那么我们可以使用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
...
}
}
}
此解决方案是否正确?或者我应该避免这种方法?我是否应该始终以完整的方式定义类/结构(异常处理,Equals
,GetHashCode
方法?
答案 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; }
}