首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >逻辑操作的基类

逻辑操作的基类
EN

Code Review用户
提问于 2015-11-23 14:15:25
回答 1查看 324关注 0票数 4

我正在开发一个用于模拟电子电路的web应用程序,并试图添加反向传播选项(猜测您可以理解为什么)。在重构过程中,我想出了一个逻辑操作的基类,并想要得到一些反馈(不管你怎么想)。类代码如下:

代码语言:javascript
复制
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);
        }
    }
}

这个类在第二个类中以如下方式使用,这个类应该是来自各个门的类:

代码语言:javascript
复制
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是以下列方式定义的枚举:

代码语言:javascript
复制
public enum LogicValue : byte
{
    Unknown = 0,
    False = 1,
    True = 2
}

对于测试部分(我也希望得到一些反馈),我使用了以下方法:

LogicOperationTests.cs

代码语言:javascript
复制
[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));
            }
        }
    }
}

以及:

TruthTableTests.cs

代码语言:javascript
复制
[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;
    }
}

和往常一样,我对任何类型的反馈都持开放态度,尽管目前我更关注的是功能和可读性,而不是性能。

如果你有任何问题,请告诉我。

EN

回答 1

Code Review用户

回答已采纳

发布于 2015-11-23 17:08:37

不要使用(如果可能)静态类。您节省了很少的字节和很少的CPU周期,但是如果需要模拟它们的实现,则很难对它们进行测试。这是一个普遍的规则,然后它可能允许例外(在这种情况下,海事组织)。

不要从方法(或属性)返回Func<LogicValue, LogicValue, LogicValue[][], int, LogicValue>。太复杂了很难弄清楚。假设您有一个有四个参数的函数(其中一个是锯齿数组),您需要了解在调用点是什么。

保持(尽可能多)连贯的名称:您有一个属性NumberOfLogicalElements,它返回_numberOfLogicalOperators。除非你有一个很好的理由,你应该选择一个名字,并在任何地方使用那个名字。它们是元素还是运算符?有什么不同吗?他们需要与众不同吗?如果是的话,那么姓名应该清楚地说明原因。

例如,在ForwardBinaryOperation中,不需要名为numberOfLogicalElements的局部变量。删除它,JIT编译器将内联属性访问。通常你应该避免这样的微观优化。

在同一个(静态)类中,您有不同的属性,ForwardBinaryOperationNotOperationTruthTable。我会将它们移到不同的类(但稍后会看到)。

您的enum值是大写的,遵循常见的大小写约定:AND不是缩略语,即使在这种情况下,也不应该用大写字母编码,把它命名为And

主要问题是LogicOperationUtilities是一个实用程序类。称它为实用工具或助手,但它总是很难闻。很多时候(并不总是),当你需要这样的课程时,实际上你在其他地方做坏事。

在您的例子中,我只需删除LogicOperationUtilities类和LogicOperation枚举,然后使用继承来完成相同的工作。

使LogicOperation成为抽象基类。说到领域语言,你可能会说:“每个逻辑操作都有一个可变的输入数和一个真值表,将每个组合映射到一个(或多个)输出值(S)”。

用于构建域模型的峰值关键字:LogicValue表示逻辑状态,Input表示LogicOperation的单个输入,Output表示单个输出。因为每个操作都可能有多个输入/输出,所以您还需要InputCollectionOutputCollection。因为一个输出可能连接到一个输入,所以可以将InputOutput的类型抽象到一个通用的Port类中。请注意,您有一个LogicValue枚举,但是在.NET中已经有相同的内置类型,加上所有C#语法糖:放弃LogicValue以支持bool?

然后添加更多内容:“每个端口都有一个名称,每个逻辑操作都可以使用该名称或它们的任意索引引用其输入/输出”。朝正确的方向走?现在,假设“每个输入端口可以从外部接收值、输入端口和从逻辑操作输出端口”。

现在您知道必须定义一个Port类(包含一个Name和一个Value属性)和两个派生类:InputPortOutputPort。每个LogicOperation类的输入都有一个属性Inputs (类型为InputCollection,几乎为空的Collection<InputPort>),还有一个Output属性(类型为OutputCollection,几乎为空的Collection<OutputPort>)。

很少有更多的细节:“这些二进制操作必须可用:以及,或者,Nand,Nor,Xor和Nxor,以及一个一元运算符”。

现在您知道有两个主要类(定义您有多少输入/输出)。定义一个抽象BinaryLogicOperation和另一个抽象UnaryLogicOperation。具体类(AndOr等)将从它们派生出来。

注意,我们将响应性从TruthTable (一个上帝类及其实用程序类)移到了适当的位置:每个类中都定义了行为,您正在使用继承来隐藏它。

那么,什么是真值表呢?TruthTable就是与LogicOperation相关联的输入(InputCollection)的组合。计算其输出列。请注意,通过这种方式,您可以构建简单的数字逻辑模拟器,只需连接输入和输出,C#事件就可以完成这项工作,请参阅以下概念的证明:

代码语言:javascript
复制
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,以便更好地与反应性扩展集成。要编写代码/构建/设计/加载您的数字网络模拟就像附加几个事件一样容易。我还建议看看任务并行库,看看解决这个问题的不同方法(它们有不同的使用场景,但在这里讨论它们是非常离题的)。

您可能已经注意到,我几乎没有编写任何代码,您已经有了很多代码,但是我试图表达的是逻辑流,代码只是这里的一个细节。

关于测试的一件事。您正在公开一个实现细节(您的实用程序类),只是为了测试它。在我看来,测试应该只检查组件的公共接口。测试公共接口应该包括所有的实现细节(代码覆盖率应该很快证实这一点)。他们不应该检查私有实现细节,因为它们可以自由更改,而且您希望确保有效的是组件行为,而不是如何实现它。如果您不能测试它,除非您测试您的实现,那么就会出现一些错误(或者您的代码过于复杂和/或无用)。顺便说一句,一个孤立的域模型也将帮助您进行测试。

票数 13
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/111586

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档