这是一个古老的问题 - 并作出回答,但是自从一直在寻找解决方案时遇到了这个问题,以下是我的看法。
public interface ITruthTable<in T1, in T2, in T3, in T4>
{
bool GetValue(T1 obj1, T2 obj2, T3 obj3, T4 obj4);
}
public static class TruthTable
{
private interface IMutableTable
{
void AddRow(bool v1, bool v2, bool v3, bool v4, bool result = false);
}
private sealed class Table<T1, T2, T3, T4>: ITruthTable<T1, T2, T3, T4>, IMutableTable
{
private readonly Func<T1, bool> _column1;
private readonly Func<T2, bool> _column2;
private readonly Func<T3, bool> _column3;
private readonly Func<T4, bool> _column4;
private readonly List<bool[]> _rows = new List<bool[]>();
private readonly List<bool> _results = new List<bool>();
private readonly bool _default;
public Table(Func<T1, bool> column1, Func<T2, bool> column2, Func<T3, bool> column3, Func<T4, bool> column4, bool defaultValue)
{
_column1 = column1;
_column2 = column2;
_column3 = column3;
_column4 = column4;
_default = defaultValue;
}
#region IMutableTable<T1,T2,T3,T4> Members
void IMutableTable.AddRow(bool v1, bool v2, bool v3, bool v4, bool result)
{
_rows.Add(new bool[4]);
var row = _rows[_rows.Count - 1];
row[0] = v1;
row[1] = v2;
row[2] = v3;
row[3] = v4;
_results.Add(result);
}
#endregion
#region ITruthTable<T1,T2,T3,T4> Members
public bool GetValue(T1 obj1, T2 obj2, T3 obj3, T4 obj4)
{
var v1 = _column1(obj1);
var v2 = _column2(obj2);
var v3 = _column3(obj3);
var v4 = _column4(obj4);
for (int i = 0; i < _rows.Count; i++)
{
var row = _rows[i];
if ((row[0] == v1) && (row[1] == v2) && (row[2] == v3) && (row[3] == v4))
return _results[i];
}
return _default;
}
#endregion
}
public static ITruthTable<T1, T2, T3, T4> Create<T1, T2, T3, T4>(Func<T1, bool> column1, Func<T2, bool> column2, Func<T3, bool> column3, Func<T4, bool> column4, bool defaultValue = false)
{
return new Table<T1, T2, T3, T4>(column1, column2, column3, column4, defaultValue);
}
public static ITruthTable<T1, T2, T3, T4> Row<T1, T2, T3, T4>(this ITruthTable<T1, T2, T3, T4> table, bool v1, bool v2, bool v3, bool v4, bool result)
{
(table as IMutableTable).AddRow(v1, v2, v3, v4, result);
return table;
}
}
class Program
{
static void Main(string[] args)
{
var testTable = TruthTable.Create<bool, bool, bool, bool>
(b => b /*Column description*/ , b => b /* Column 2 */ , b => b, b => b, defaultValue: false)
.Row(false, false, false, false, false)
.Row(false, true, false, true, true)
.Row(true, true, true, false, false)
.Row(true, false, true, true, true);
var result = testTable.GetValue(false, true, false, true);
}
简单的解释:funcs为每列提供accept值并将它们转换为bools。一个简单的循环然后找到第一个正确的匹配并返回结果值或返回指定的默认值。如果输入与该行匹配,每个.Row调用的最后一个值就是结果。
当然,这个解决方案适用于4个通用参数,但写入表格的参数比这个更多或更少的参数很简单。另外,上面这个简单的例子使用bool来为值提取器进行bool映射,但在真实世界的应用程序中,它可能需要接受某些其他类型的对象并将其转换为该列的bool输入值。
这是类型安全的,足够好我的需求,希望它可以帮助别人。
Pfew,64个有意义的名字。我已经觉得很难拿出一个。如果我选择这个选项,我仍然会遇到问题,根据六个标志中的每一个的值确定正确的键。除非我从'1,2,4,8,16,32'中为每个标志分配一个int并将它们放在一起。这使我非常接近使用'byte'或'int'作为关键字。 – 2010-09-09 13:10:21
@Ronald Wildenberg - 双OR-在一起的权力选项正是FlagsAttribute的意图。所以你只需要六个命名值而不是64. – 2010-09-09 13:13:07
@Jeffrey - 你说得对,我的错。你不需要考虑64个名字。谢谢。 – 2010-09-09 13:15:42