我正在开发一个用于模拟电子电路的web应用程序,并试图添加反向传播选项(猜测您可以理解为什么)。在重构过程中,我想出了一个逻辑操作的基类,并想要得到一些反馈(不管你怎么想)。类代码如下:
public static class LogicOperationUtilities
{
private static readonly int _numberOfLogicalOperators = Enum.GetValues(typeof(LogicValue)).Length;
/// <summary>
/// Get the number of logical elements.
/// </summary>
public static int NumberOfLogicalElements
{
get { return _numberOfLogicalOperators; }
}
public static Func<LogicValue, LogicValue, LogicValue[][], int, LogicValue> ForwardBinaryOperation
{
get
{
return (x, y, truthTable, numberOfElements) =>
{
int numberOfLogicalElements = NumberOfLogicalElements;
// this works only if assignment of _combinations is done in this way:
// _combinations = new LogicalValue[][]
// {
// new LogicalValue[] { LogicalValue.Unknown, LogicalValue.Unknown, Result },
// new LogicalValue[] { LogicalValue.Unknown, LogicalValue.False, Result },
// new LogicalValue[] { LogicalValue.Unknown, LogicalValue.True, Result },
// new LogicalValue[] { LogicalValue.False, LogicalValue.Unknown, Result },
// new LogicalValue[] { LogicalValue.False, LogicalValue.False, Result },
// new LogicalValue[] { LogicalValue.False, LogicalValue.True, Result },
// new LogicalValue[] { LogicalValue.True, LogicalValue.Unknown, Result },
// new LogicalValue[] { LogicalValue.True, LogicalValue.False, Result },
// new LogicalValue[] { LogicalValue.True, LogicalValue.True, Result }
// };
int rowNumber = (numberOfLogicalElements * (int)x) + (int)y;
return truthTable[rowNumber][numberOfLogicalElements - 1];
};
}
}
public static Func<LogicValue, LogicValue[][], int, IEnumerable<Tuple<LogicValue, LogicValue>>> BackwardBinaryOperation
{
get
{
return (x, truthTable, numberOfElements)
=> truthTable.Where(combination => combination[numberOfElements - 1] == x)
.Select(combination => new Tuple<LogicValue, LogicValue>(combination[0], combination[1]));
}
}
// Not operation
//
public static LogicValue[][] NotOperationTruthTable
{
get
{
return new LogicValue[][]
{
new LogicValue[] { LogicValue.Unknown, LogicValue.Unknown},
new LogicValue[] { LogicValue.False, LogicValue.True},
new LogicValue[] { LogicValue.True, LogicValue.False}
};
}
}
private static readonly int _notOperationNumberOfCombinations = NotOperationTruthTable.Length;
private static readonly int _notOperationNumberOfElements = NotOperationTruthTable[0].Length;
/// <summary>
/// Get the function that calculates the result of the Not operation.
/// </summary>
public static Func<LogicValue, LogicValue> ForwardNotOperation
{
get { return (x) => NotOperationTruthTable[(byte)x][1]; }
}
/// <summary>
/// Get the function that calculates the input values that give a certain specified output.
/// </summary>
public static Func<LogicValue, IEnumerable<LogicValue>> BackwardNotOperation
{
get
{
return (x) => NotOperationTruthTable.Where(combination => combination[1] == x)
.Select(combination => combination[0]);
}
}
// AND operation
//
/// <summary>
/// The truth table for the logical AND operation
/// </summary>
public static LogicValue[][] AndOperationTruthTable
{
get
{
return new LogicValue[][]
{
new LogicValue[] { LogicValue.Unknown, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.False, LogicValue.False },
new LogicValue[] { LogicValue.Unknown, LogicValue.True, LogicValue.Unknown },
new LogicValue[] { LogicValue.False, LogicValue.Unknown, LogicValue.False },
new LogicValue[] { LogicValue.False, LogicValue.False, LogicValue.False },
new LogicValue[] { LogicValue.False, LogicValue.True, LogicValue.False },
new LogicValue[] { LogicValue.True, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.True, LogicValue.False, LogicValue.False },
new LogicValue[] { LogicValue.True, LogicValue.True, LogicValue.True }
};
}
}
private static readonly int _andOperationNumberOfCombinations = AndOperationTruthTable.Length;
private static readonly int _andOperationNumberOfElements = AndOperationTruthTable[0].Length;
public static Func<LogicValue, LogicValue, LogicValue> ForwardAndOperation
{
get
{
return (x, y) => ForwardBinaryOperation(x, y, AndOperationTruthTable, _andOperationNumberOfElements);
}
}
public static Func<LogicValue, IEnumerable<Tuple<LogicValue, LogicValue>>> BackwardAndOperation
{
get
{
return (x) => BackwardBinaryOperation(x, AndOperationTruthTable, _andOperationNumberOfElements);
}
}
// NAND operation
//
public static LogicValue[][] NandOperationTruthTable
{
get
{
return new LogicValue[][]
{
new LogicValue[] { LogicValue.Unknown, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.False, LogicValue.True },
new LogicValue[] { LogicValue.Unknown, LogicValue.True, LogicValue.Unknown },
new LogicValue[] { LogicValue.False, LogicValue.Unknown, LogicValue.True },
new LogicValue[] { LogicValue.False, LogicValue.False, LogicValue.True },
new LogicValue[] { LogicValue.False, LogicValue.True, LogicValue.True },
new LogicValue[] { LogicValue.True, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.True, LogicValue.False, LogicValue.True },
new LogicValue[] { LogicValue.True, LogicValue.True, LogicValue.False }
};
}
}
private static readonly int _nandOperationNumberOfCombinations = NandOperationTruthTable.Length;
private static readonly int _nandOperationNumberOfElements = NandOperationTruthTable[0].Length;
public static Func<LogicValue, LogicValue, LogicValue> ForwardNandOperation
{
get
{
return (x, y) => ForwardBinaryOperation(x, y, NandOperationTruthTable, _nandOperationNumberOfElements);
}
}
public static Func<LogicValue, IEnumerable<Tuple<LogicValue, LogicValue>>> BackwardNandOperation
{
get { return (x) => BackwardBinaryOperation(x, NandOperationTruthTable, _nandOperationNumberOfElements); }
}
// OR operation
//
public static LogicValue[][] OrOperationTruthTable
{
get
{
return new LogicValue[][]
{
new LogicValue[] { LogicValue.Unknown, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.False, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.True, LogicValue.True },
new LogicValue[] { LogicValue.False, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.False, LogicValue.False, LogicValue.False },
new LogicValue[] { LogicValue.False, LogicValue.True, LogicValue.True },
new LogicValue[] { LogicValue.True, LogicValue.Unknown, LogicValue.True },
new LogicValue[] { LogicValue.True, LogicValue.False, LogicValue.True },
new LogicValue[] { LogicValue.True, LogicValue.True, LogicValue.True }
};
}
}
private static readonly int _orOperationNumberOfCombinations = OrOperationTruthTable.Length;
private static readonly int _orOperationNumberOfElements = OrOperationTruthTable[0].Length;
public static Func<LogicValue, LogicValue, LogicValue> ForwardOrOperation
{
get
{
return (x, y) => ForwardBinaryOperation(x, y, OrOperationTruthTable, _orOperationNumberOfElements);
}
}
public static Func<LogicValue, IEnumerable<Tuple<LogicValue, LogicValue>>> BackwardOrOperation
{
get { return (x) => BackwardBinaryOperation(x, OrOperationTruthTable, _orOperationNumberOfElements); }
}
// NOR operation
//
public static LogicValue[][] NorOperationTruthTable
{
get
{
return new LogicValue[][]
{
new LogicValue[] { LogicValue.Unknown, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.False, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.True, LogicValue.False },
new LogicValue[] { LogicValue.False, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.False, LogicValue.False, LogicValue.True },
new LogicValue[] { LogicValue.False, LogicValue.True, LogicValue.False },
new LogicValue[] { LogicValue.True, LogicValue.Unknown, LogicValue.False },
new LogicValue[] { LogicValue.True, LogicValue.False, LogicValue.False },
new LogicValue[] { LogicValue.True, LogicValue.True, LogicValue.False }
};
}
}
private static readonly int _norOperationNumberOfCombinations = NorOperationTruthTable.Length;
private static readonly int _norOperationNumberOfElements = NorOperationTruthTable[0].Length;
public static Func<LogicValue, LogicValue, LogicValue> ForwardNorOperation
{
get
{
return (x, y) => ForwardBinaryOperation(x, y, NorOperationTruthTable, _norOperationNumberOfElements);
}
}
public static Func<LogicValue, IEnumerable<Tuple<LogicValue, LogicValue>>> BackwardNorOperation
{
get { return (x) => BackwardBinaryOperation(x, NorOperationTruthTable, _norOperationNumberOfElements); }
}
// XOR operation
//
public static LogicValue[][] XorOperationTruthTable
{
get
{
return new LogicValue[][]
{
new LogicValue[] { LogicValue.Unknown, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.False, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.True, LogicValue.Unknown },
new LogicValue[] { LogicValue.False, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.False, LogicValue.False, LogicValue.False },
new LogicValue[] { LogicValue.False, LogicValue.True, LogicValue.True },
new LogicValue[] { LogicValue.True, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.True, LogicValue.False, LogicValue.True },
new LogicValue[] { LogicValue.True, LogicValue.True, LogicValue.False }
};
}
}
private static readonly int _xorOperationNumberOfCombinations = XorOperationTruthTable.Length;
private static readonly int _xorOperationNumberOfElements = XorOperationTruthTable[0].Length;
public static Func<LogicValue, LogicValue, LogicValue> ForwardXorOperation
{
get
{
return (x, y) => ForwardBinaryOperation(x, y, XorOperationTruthTable, _xorOperationNumberOfElements);
}
}
public static Func<LogicValue, IEnumerable<Tuple<LogicValue, LogicValue>>> BackwardXorOperation
{
get
{
return (x) => BackwardBinaryOperation(x, XorOperationTruthTable, _xorOperationNumberOfElements);
}
}
// NXOR operation
//
public static LogicValue[][] NxorOperationTruthTable
{
get
{
return new LogicValue[][]
{
new LogicValue[] { LogicValue.Unknown, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.False, LogicValue.Unknown },
new LogicValue[] { LogicValue.Unknown, LogicValue.True, LogicValue.Unknown },
new LogicValue[] { LogicValue.False, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.False, LogicValue.False, LogicValue.True },
new LogicValue[] { LogicValue.False, LogicValue.True, LogicValue.False },
new LogicValue[] { LogicValue.True, LogicValue.Unknown, LogicValue.Unknown },
new LogicValue[] { LogicValue.True, LogicValue.False, LogicValue.False },
new LogicValue[] { LogicValue.True, LogicValue.True, LogicValue.True }
};
}
}
private static readonly int _nxorOperationNumberOfCombinations = NxorOperationTruthTable.Length;
private static readonly int _nxorOperationNumberOfElements = NxorOperationTruthTable[0].Length;
public static Func<LogicValue, LogicValue, LogicValue> ForwardNxorOperation
{
get
{
return (x, y) => ForwardBinaryOperation(x, y, NxorOperationTruthTable, _nxorOperationNumberOfElements);
}
}
public static Func<LogicValue, IEnumerable<Tuple<LogicValue, LogicValue>>> BackwardNxorOperation
{
get
{
return (x) => BackwardBinaryOperation(x, NxorOperationTruthTable, _nxorOperationNumberOfElements);
}
}
}这个类在第二个类中以如下方式使用,这个类应该是来自各个门的类:
public class TruthTable
{
private readonly LogicValue[][] _truthTable;
/// <summary>
/// The types of logic operations.
/// </summary>
public enum LogicOperation
{
NOT,
AND,
OR,
XOR,
NAND,
NOR,
NXOR
}
/// <summary>
/// Get the logic operation this TruthTable instance refers to.
/// </summary>
public LogicOperation Operation { get; private set; }
/// <summary>
/// Get a flag indicating if the truth table is of a
/// binary operation or not.
/// </summary>
public bool IsBinaryOperation
{
get { return Operation != LogicOperation.NOT; }
}
/// <summary>
/// Get the truth table (as a matrix) for the specified
/// logic operation.
/// </summary>
public LogicValue[,] OperationTruthTable
{
get
{
int numberOfCombinations = _truthTable.Length;
int numberOfElements = _truthTable[0].Length;
var result = new LogicValue[numberOfCombinations, numberOfElements];
for (int i = 0; i < numberOfCombinations; i++)
{
for (int j = 0; j < numberOfElements; j++)
{
result[i, j] = _truthTable[i][j];
}
}
return result;
}
}
/// <summary>
/// Get the result value of a unary logic operation with
/// input x.
/// </summary>
/// <returns>
/// The result of the unary operation with input x.
/// </returns>
public LogicValue this[LogicValue x]
{
get
{
if (IsBinaryOperation)
{
throw new InvalidOperationException(
"This operation is valid only for unary operations.");
}
return _truthTable[(int)x][1];
}
}
/// <summary>
/// Get the result value of a binary logic operation with
/// input x and y.
/// </summary>
/// <returns>
/// The result of the binary operation with input x and y.
/// </returns>
public LogicValue this[LogicValue x, LogicValue y]
{
get
{
if (!IsBinaryOperation)
{
throw new InvalidOperationException(
"This operation is valid only for binary operations.");
}
return _truthTable[3 * (int)x + (int)y][2];
}
}
/// <summary>
/// Constructor of a TruthTable instance.
/// </summary>
/// <param name="logicOperation">
/// The logic operation this truth table refers to.
/// </param>
public TruthTable(LogicOperation logicOperation)
{
switch (logicOperation)
{
case LogicOperation.AND:
_truthTable = LogicOperationUtilities.AndOperationTruthTable;
break;
case LogicOperation.NAND:
_truthTable = LogicOperationUtilities.NandOperationTruthTable;
break;
case LogicOperation.NOR:
_truthTable = LogicOperationUtilities.NorOperationTruthTable;
break;
case LogicOperation.NOT:
_truthTable = LogicOperationUtilities.NotOperationTruthTable;
break;
case LogicOperation.NXOR:
_truthTable = LogicOperationUtilities.NxorOperationTruthTable;
break;
case LogicOperation.OR:
_truthTable = LogicOperationUtilities.OrOperationTruthTable;
break;
case LogicOperation.XOR:
_truthTable = LogicOperationUtilities.XorOperationTruthTable;
break;
}
Operation = logicOperation;
}
}仅为了完成该场景,LogicValue是以下列方式定义的枚举:
public enum LogicValue : byte
{
Unknown = 0,
False = 1,
True = 2
}对于测试部分(我也希望得到一些反馈),我使用了以下方法:
[TestClass]
public class LogicOperationTests
{
[TestMethod]
public void ForwardNotOperationTest()
{
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNotOperation(LogicValue.Unknown));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNotOperation(LogicValue.False));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNotOperation(LogicValue.True));
}
[TestMethod]
public void BackwardNotOperationTest()
{
foreach (LogicValue value in Enum.GetValues(typeof(LogicValue)))
{
foreach (var logicalValue in LogicOperationUtilities.BackwardNotOperation(value))
{
Assert.AreEqual(value, LogicOperationUtilities.ForwardNotOperation(logicalValue));
}
}
}
[TestMethod]
public void ForwardAndOperationTest()
{
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardAndOperation(LogicValue.Unknown, LogicValue.Unknown));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardAndOperation(LogicValue.Unknown, LogicValue.False));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardAndOperation(LogicValue.Unknown, LogicValue.True));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardAndOperation(LogicValue.False, LogicValue.Unknown));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardAndOperation(LogicValue.False, LogicValue.False));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardAndOperation(LogicValue.False, LogicValue.True));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardAndOperation(LogicValue.True, LogicValue.Unknown));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardAndOperation(LogicValue.True, LogicValue.False));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardAndOperation(LogicValue.True, LogicValue.True));
}
[TestMethod]
public void BackwardAndOperationTest()
{
foreach (LogicValue value in Enum.GetValues(typeof(LogicValue)))
{
foreach (var logicalValue in LogicOperationUtilities.BackwardAndOperation(value))
{
Assert.AreEqual(value, LogicOperationUtilities.ForwardAndOperation(logicalValue.Item1, logicalValue.Item2));
}
}
}
[TestMethod]
public void ForwardNandOperationTest()
{
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNandOperation(LogicValue.Unknown, LogicValue.Unknown));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNandOperation(LogicValue.Unknown, LogicValue.False));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNandOperation(LogicValue.Unknown, LogicValue.True));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNandOperation(LogicValue.False, LogicValue.Unknown));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNandOperation(LogicValue.False, LogicValue.False));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNandOperation(LogicValue.False, LogicValue.True));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNandOperation(LogicValue.True, LogicValue.Unknown));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNandOperation(LogicValue.True, LogicValue.False));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNandOperation(LogicValue.True, LogicValue.True));
}
[TestMethod]
public void BackwardNandOperationTest()
{
foreach (LogicValue value in Enum.GetValues(typeof(LogicValue)))
{
foreach (var logicalValue in LogicOperationUtilities.BackwardNandOperation(value))
{
Assert.AreEqual(value, LogicOperationUtilities.ForwardNandOperation(logicalValue.Item1, logicalValue.Item2));
}
}
}
[TestMethod]
public void ForwardOrOperationTest()
{
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardOrOperation(LogicValue.Unknown, LogicValue.Unknown));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardOrOperation(LogicValue.Unknown, LogicValue.False));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardOrOperation(LogicValue.Unknown, LogicValue.True));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardOrOperation(LogicValue.False, LogicValue.Unknown));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardOrOperation(LogicValue.False, LogicValue.False));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardOrOperation(LogicValue.False, LogicValue.True));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardOrOperation(LogicValue.True, LogicValue.Unknown));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardOrOperation(LogicValue.True, LogicValue.False));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardOrOperation(LogicValue.True, LogicValue.True));
}
[TestMethod]
public void BackwardOrOperationTest()
{
foreach (LogicValue value in Enum.GetValues(typeof(LogicValue)))
{
foreach (var logicalValue in LogicOperationUtilities.BackwardOrOperation(value))
{
Assert.AreEqual(value, LogicOperationUtilities.ForwardOrOperation(logicalValue.Item1, logicalValue.Item2));
}
}
}
[TestMethod]
public void ForwardNorOperationTest()
{
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNorOperation(LogicValue.Unknown, LogicValue.Unknown));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNorOperation(LogicValue.Unknown, LogicValue.False));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNorOperation(LogicValue.Unknown, LogicValue.True));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNorOperation(LogicValue.False, LogicValue.Unknown));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNorOperation(LogicValue.False, LogicValue.False));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNorOperation(LogicValue.False, LogicValue.True));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNorOperation(LogicValue.True, LogicValue.Unknown));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNorOperation(LogicValue.True, LogicValue.False));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNorOperation(LogicValue.True, LogicValue.True));
}
[TestMethod]
public void BackwardNorOperationTest()
{
foreach (LogicValue value in Enum.GetValues(typeof(LogicValue)))
{
foreach (var logicalValue in LogicOperationUtilities.BackwardNorOperation(value))
{
Assert.AreEqual(value, LogicOperationUtilities.ForwardNorOperation(logicalValue.Item1, logicalValue.Item2));
}
}
}
[TestMethod]
public void ForwardXorOperationTest()
{
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardXorOperation(LogicValue.Unknown, LogicValue.Unknown));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardXorOperation(LogicValue.Unknown, LogicValue.False));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardXorOperation(LogicValue.Unknown, LogicValue.True));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardXorOperation(LogicValue.False, LogicValue.Unknown));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardXorOperation(LogicValue.False, LogicValue.False));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardXorOperation(LogicValue.False, LogicValue.True));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardXorOperation(LogicValue.True, LogicValue.Unknown));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardXorOperation(LogicValue.True, LogicValue.False));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardXorOperation(LogicValue.True, LogicValue.True));
}
[TestMethod]
public void BackwardXorOperationTest()
{
foreach (LogicValue value in Enum.GetValues(typeof(LogicValue)))
{
foreach (var logicalValue in LogicOperationUtilities.BackwardXorOperation(value))
{
Assert.AreEqual(value, LogicOperationUtilities.ForwardXorOperation(logicalValue.Item1, logicalValue.Item2));
}
}
}
[TestMethod]
public void ForwardNxorOperationTest()
{
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNxorOperation(LogicValue.Unknown, LogicValue.Unknown));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNxorOperation(LogicValue.Unknown, LogicValue.False));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNxorOperation(LogicValue.Unknown, LogicValue.True));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNxorOperation(LogicValue.False, LogicValue.Unknown));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNxorOperation(LogicValue.False, LogicValue.False));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNxorOperation(LogicValue.False, LogicValue.True));
Assert.AreEqual(LogicValue.Unknown, LogicOperationUtilities.ForwardNxorOperation(LogicValue.True, LogicValue.Unknown));
Assert.AreEqual(LogicValue.False, LogicOperationUtilities.ForwardNxorOperation(LogicValue.True, LogicValue.False));
Assert.AreEqual(LogicValue.True, LogicOperationUtilities.ForwardNxorOperation(LogicValue.True, LogicValue.True));
}
[TestMethod]
public void BackwardNxorOperationTest()
{
foreach (LogicValue value in Enum.GetValues(typeof(LogicValue)))
{
foreach (var logicalValue in LogicOperationUtilities.BackwardNxorOperation(value))
{
Assert.AreEqual(value, LogicOperationUtilities.ForwardNxorOperation(logicalValue.Item1, logicalValue.Item2));
}
}
}
}以及:
[TestClass]
public class TruthTableTests
{
[TestMethod]
public void AndTruthTableCreationTest()
{
TruthTable table = new TruthTable(TruthTable.LogicOperation.AND);
Assert.IsTrue(table.IsBinaryOperation);
Assert.IsTrue(HaveSameSize(LogicOperationUtilities.AndOperationTruthTable, table.OperationTruthTable));
Assert.IsTrue(ContainSameElements(LogicOperationUtilities.AndOperationTruthTable, table.OperationTruthTable));
}
[TestMethod]
public void NandTruthTableCreationTest()
{
TruthTable table = new TruthTable(TruthTable.LogicOperation.NAND);
Assert.IsTrue(table.IsBinaryOperation);
Assert.IsTrue(HaveSameSize(LogicOperationUtilities.NandOperationTruthTable, table.OperationTruthTable));
Assert.IsTrue(ContainSameElements(LogicOperationUtilities.NandOperationTruthTable, table.OperationTruthTable));
}
[TestMethod]
public void OrTruthTableCreationTest()
{
TruthTable table = new TruthTable(TruthTable.LogicOperation.OR);
Assert.IsTrue(table.IsBinaryOperation);
Assert.IsTrue(HaveSameSize(LogicOperationUtilities.OrOperationTruthTable, table.OperationTruthTable));
Assert.IsTrue(ContainSameElements(LogicOperationUtilities.OrOperationTruthTable, table.OperationTruthTable));
}
[TestMethod]
public void NorTruthTableCreationTest()
{
TruthTable table = new TruthTable(TruthTable.LogicOperation.NOR);
Assert.IsTrue(table.IsBinaryOperation);
Assert.IsTrue(HaveSameSize(LogicOperationUtilities.NorOperationTruthTable, table.OperationTruthTable));
Assert.IsTrue(ContainSameElements(LogicOperationUtilities.NorOperationTruthTable, table.OperationTruthTable));
}
[TestMethod]
public void NotTruthTableCreationTest()
{
TruthTable table = new TruthTable(TruthTable.LogicOperation.NOT);
Assert.IsFalse(table.IsBinaryOperation);
Assert.IsTrue(HaveSameSize(LogicOperationUtilities.NotOperationTruthTable, table.OperationTruthTable));
Assert.IsTrue(ContainSameElements(LogicOperationUtilities.NotOperationTruthTable, table.OperationTruthTable));
}
[TestMethod]
public void XorTruthTableCreationTest()
{
TruthTable table = new TruthTable(TruthTable.LogicOperation.XOR);
Assert.IsTrue(table.IsBinaryOperation);
Assert.IsTrue(HaveSameSize(LogicOperationUtilities.XorOperationTruthTable, table.OperationTruthTable));
Assert.IsTrue(ContainSameElements(LogicOperationUtilities.XorOperationTruthTable, table.OperationTruthTable));
}
[TestMethod]
public void NxorTruthTableCreationTest()
{
TruthTable table = new TruthTable(TruthTable.LogicOperation.NXOR);
Assert.IsTrue(table.IsBinaryOperation);
Assert.IsTrue(HaveSameSize(LogicOperationUtilities.NxorOperationTruthTable, table.OperationTruthTable));
Assert.IsTrue(ContainSameElements(LogicOperationUtilities.NxorOperationTruthTable, table.OperationTruthTable));
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void IndexOperatorTest()
{
TruthTable unary = new TruthTable(TruthTable.LogicOperation.NOT);
TruthTable binary = new TruthTable(TruthTable.LogicOperation.AND);
var values = Enum.GetValues(typeof(LogicValue));
var shouldFail = unary[LogicValue.False, LogicValue.False];
var shouldAlsoFail = binary[LogicValue.False];
foreach (LogicValue x in values)
{
Assert.AreSame(unary[x], LogicOperationUtilities.ForwardNotOperation(x));
foreach (LogicValue y in values)
{
Assert.AreSame(binary[x, y], LogicOperationUtilities.ForwardAndOperation(x, y));
}
}
}
public bool HaveSameSize(LogicValue[][] truthTable, LogicValue[,] truthTableMatrix)
{
if (truthTable.Length != truthTableMatrix.GetLength(0))
{
return false;
}
var numberOfColumns = truthTableMatrix.GetLength(1);
for (int i = 0; i < truthTable.Length; i++)
{
if (truthTable[i].Length != numberOfColumns)
{
return false;
}
}
return true;
}
public bool ContainSameElements(LogicValue[][] truthTable, LogicValue[,] truthTableMatrix)
{
var rows = truthTable.Length;
var cols = truthTableMatrix.GetLength(1);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (truthTable[i][j] != truthTableMatrix[i, j])
{
return false;
}
}
}
return true;
}
}和往常一样,我对任何类型的反馈都持开放态度,尽管目前我更关注的是功能和可读性,而不是性能。
如果你有任何问题,请告诉我。
发布于 2015-11-23 17:08:37
不要使用(如果可能)静态类。您节省了很少的字节和很少的CPU周期,但是如果需要模拟它们的实现,则很难对它们进行测试。这是一个普遍的规则,然后它可能允许例外(在这种情况下,海事组织)。
不要从方法(或属性)返回Func<LogicValue, LogicValue, LogicValue[][], int, LogicValue>。太复杂了很难弄清楚。假设您有一个有四个参数的函数(其中一个是锯齿数组),您需要了解在调用点是什么。
保持(尽可能多)连贯的名称:您有一个属性NumberOfLogicalElements,它返回_numberOfLogicalOperators。除非你有一个很好的理由,你应该选择一个名字,并在任何地方使用那个名字。它们是元素还是运算符?有什么不同吗?他们需要与众不同吗?如果是的话,那么姓名应该清楚地说明原因。
例如,在ForwardBinaryOperation中,不需要名为numberOfLogicalElements的局部变量。删除它,JIT编译器将内联属性访问。通常你应该避免这样的微观优化。
在同一个(静态)类中,您有不同的属性,ForwardBinaryOperation和NotOperationTruthTable。我会将它们移到不同的类(但稍后会看到)。
您的enum值是大写的,遵循常见的大小写约定:AND不是缩略语,即使在这种情况下,也不应该用大写字母编码,把它命名为And。
主要问题是LogicOperationUtilities是一个实用程序类。称它为实用工具或助手,但它总是很难闻。很多时候(并不总是),当你需要这样的课程时,实际上你在其他地方做坏事。
在您的例子中,我只需删除LogicOperationUtilities类和LogicOperation枚举,然后使用继承来完成相同的工作。
使LogicOperation成为抽象基类。说到领域语言,你可能会说:“每个逻辑操作都有一个可变的输入数和一个真值表,将每个组合映射到一个(或多个)输出值(S)”。
用于构建域模型的峰值关键字:LogicValue表示逻辑状态,Input表示LogicOperation的单个输入,Output表示单个输出。因为每个操作都可能有多个输入/输出,所以您还需要InputCollection和OutputCollection。因为一个输出可能连接到一个输入,所以可以将Input和Output的类型抽象到一个通用的Port类中。请注意,您有一个LogicValue枚举,但是在.NET中已经有相同的内置类型,加上所有C#语法糖:放弃LogicValue以支持bool?。
然后添加更多内容:“每个端口都有一个名称,每个逻辑操作都可以使用该名称或它们的任意索引引用其输入/输出”。朝正确的方向走?现在,假设“每个输入端口可以从外部接收值、输入端口和从逻辑操作输出端口”。
现在您知道必须定义一个Port类(包含一个Name和一个Value属性)和两个派生类:InputPort和OutputPort。每个LogicOperation类的输入都有一个属性Inputs (类型为InputCollection,几乎为空的Collection<InputPort>),还有一个Output属性(类型为OutputCollection,几乎为空的Collection<OutputPort>)。
很少有更多的细节:“这些二进制操作必须可用:以及,或者,Nand,Nor,Xor和Nxor,以及一个一元运算符”。
现在您知道有两个主要类(定义您有多少输入/输出)。定义一个抽象BinaryLogicOperation和另一个抽象UnaryLogicOperation。具体类(And、Or等)将从它们派生出来。
注意,我们将响应性从TruthTable (一个上帝类及其实用程序类)移到了适当的位置:每个类中都定义了行为,您正在使用继承来隐藏它。
那么,什么是真值表呢?TruthTable就是与LogicOperation相关联的输入(InputCollection)的组合。计算其输出列。请注意,通过这种方式,您可以构建简单的数字逻辑模拟器,只需连接输入和输出,C#事件就可以完成这项工作,请参阅以下概念的证明:
abstract class Port {
public bool? Value {
get { return _value; }
set {
if (_value != value) {
_value = value;
OnValueChanged(EventArgs.Empty);
}
}
public event EventHandler ValueChanged;
protected virtual void OnValueChanged(EventArgs e) {
var valueChanged = ValueChanged;
if (valueChanged != null) {
valueChanged(this, e);
}
}
}
private bool? _value;
}在此基础上,您应该添加INotifyPropertyChanged实现,可能的话,添加IObservable,以便更好地与反应性扩展集成。要编写代码/构建/设计/加载您的数字网络模拟就像附加几个事件一样容易。我还建议看看任务并行库,看看解决这个问题的不同方法(它们有不同的使用场景,但在这里讨论它们是非常离题的)。
您可能已经注意到,我几乎没有编写任何代码,您已经有了很多代码,但是我试图表达的是逻辑流,代码只是这里的一个细节。
关于测试的一件事。您正在公开一个实现细节(您的实用程序类),只是为了测试它。在我看来,测试应该只检查组件的公共接口。测试公共接口应该包括所有的实现细节(代码覆盖率应该很快证实这一点)。他们不应该检查私有实现细节,因为它们可以自由更改,而且您希望确保有效的是组件行为,而不是如何实现它。如果您不能测试它,除非您测试您的实现,那么就会出现一些错误(或者您的代码过于复杂和/或无用)。顺便说一句,一个孤立的域模型也将帮助您进行测试。
https://codereview.stackexchange.com/questions/111586
复制相似问题