3

我有一个几年前写的程序,用来为字节找到“好的”二进制运算符;byteA左乘 byteB得到 byte C。运算符定义为 256x256 字节矩阵。A类实现的精简版本如下。

Equals()为真 IFF 数组中的所有 65536 个字节都相同。

CompareTo()将运算符的线性度与线性度更高(对加密不利)与线性度更低(对加密有利)的连续体进行比较。

因此,对于两个实例AB,以下两个都为真是可能的:

A.Equals(B) = false
(A.ComparesTo(B) == 0) = true

我的问题更少:这是个好主意吗?我知道答案是否定的,但考虑到测量线性度的巨大计算成本和我的问题的狭窄性质,这个设计是可行的。代码也类似于:

if (localMinimumOperator < globalMinimumOperator)
{
  localMinimumOperator = globalMinimumOperator;
}

我更容易阅读。

我的问题是:==、CompareTo()== 0和之间的这种分歧的后果是什么Equals()?或者:是否有描述哪个扩展使用哪个接口的 LINQ 扩展方法列表(IEquatableIComparable)的哪些 LINQ 扩展方法的列表?

比这篇 MSDN 文章更简洁的东西Enumerable

例如:

IEnumerable<BinaryOperation> distinct = orgList.Distinct();

Equals(BinaryOperator)按以下方式调用: Enumerable.Distinct<TSource>Method as does Contains()。我明白这一点Sort()OrderBy()使用对CompareTo().

但是FindFirst()BinarySearch()呢?

我的示例类:

using System;
using System.Collections.Generic;
using System.Linq;


namespace Jww05
{
  public class BinaryOperation : IEquatable<BinaryOperation>, IComparable<BinaryOperation>
  {
    #region ClassMembers

    public List<List<byte>> TruthTable
    {
      get
      {
        // I don't like giving out the underlying list if I help it
        var retVal = new List<List<byte>>(OperatorDefintion);
        return retVal;
      }
    }

    // private data store for TruthTable
    private List<List<byte>> OperatorDefintion { get; set; }

    public BinaryOperation()
    {
      // initial state is the Identity operator
      OperatorDefintion = new List<List<byte>>();
      for (int i = 0; i < 256; i++)
      {
        var curRow = new List<byte>();
        for (int j = 0; j < 256; j++)
        {
          curRow.Add((byte)(i + j));
        }
        OperatorDefintion.Add(curRow);
      }
    }

    private long MeasureOperatorLinearity()
    {
      var diagonalOffsets = new byte[] { 255, 0, 1 };

      /*
       * Code that measures linearity in the original code used the Fast Walsh Hadamard Transform.
       * That should go here, but it is removed because the FWHT is clutter for the purposes of this question.
       *
       * Since I needed a stub for this, I decided to exacerbate the differnece
       * between CompareTo() == 0 and Equals()
       * by returning an arbitrary int in lieu of the long CPU intensive Fast Walsh Hadamard Transform.
       *
       * If the matrices are identical on an element-by-element basis, then the Faux Linearity will be the the same.
       * If the faux linearity (sum of terms on the main diagonal and corners) are the same, the underlying matrices could be different on an element-by-element basis.
       */
      long fauxLinearityMeasure = 0;
      for (var currRow = 0; currRow < OperatorDefintion.Count(); ++currRow)
      {
        fauxLinearityMeasure *= 5;
        fauxLinearityMeasure = diagonalOffsets.Select(diagonalOffset => (byte)(currRow + diagonalOffset))
                                              .Aggregate(fauxLinearityMeasure, (current, offestedIndex) => current + (OperatorDefintion[offestedIndex][currRow]));
      }

      return (int)fauxLinearityMeasure;
    }

    #endregion ClassMembers

    #region ComparisonOperations

    public int CompareTo(BinaryOperation other)
    {
      long otherLinearity = other.MeasureOperatorLinearity();
      long thisLinearity = MeasureOperatorLinearity();
      long linearityDiff = thisLinearity - otherLinearity;

      // case the differnece of the linarity measures into {-1, 0, 1}
      return (0 < linearityDiff) ? 1
           : (0 > linearityDiff) ? -1
           : 0;
    }

    public static bool operator >(BinaryOperation lhs, BinaryOperation rhs)
    {
      if (ReferenceEquals(null, lhs) ||
          ReferenceEquals(null, rhs))
      {
        return false;
      }
      return (0 < lhs.CompareTo(rhs));
    }

    public static bool operator <(BinaryOperation lhs, BinaryOperation rhs)
    {
      if (ReferenceEquals(null, lhs) ||
          ReferenceEquals(null, rhs))
      {
        return false;
      }
      return (0 > lhs.CompareTo(rhs));
    }

    public static bool operator <=(BinaryOperation lhs, BinaryOperation rhs)
    {
      if (ReferenceEquals(null, lhs) ||
          ReferenceEquals(null, rhs))
      {
        return false;
      }

      // equals is cheap
      if (lhs.Equals(rhs))
      {
        return true;
      }

      return (0 > lhs.CompareTo(rhs));
    }

    public static bool operator >=(BinaryOperation lhs, BinaryOperation rhs)
    {
      if (ReferenceEquals(null, lhs) ||
          ReferenceEquals(null, rhs))
      {
        return false;
      }

      // equals is cheap
      if (lhs.Equals(rhs))
      {
        return true;
      }

      return (0 < lhs.CompareTo(rhs));
    }

    #endregion ComparisonOperations

    #region EqualityOperators

    public bool Equals(BinaryOperation other)
    {
      if (ReferenceEquals(null, other))
      {
        return false;
      }

      var otherTruthTable = other.TruthTable;
      var thisTruthTable = TruthTable;
      var isEquals = true;
      for (int currRow = 0; currRow < thisTruthTable.Count(); ++currRow)
      {
        isEquals = isEquals && thisTruthTable[currRow].SequenceEqual(otherTruthTable[currRow]);
      }

      return isEquals;
    }

    public override bool Equals(object obj)
    {
      return Equals(obj as BinaryOperation);
    }

    public override int GetHashCode()
    {
      return OperatorDefintion.SelectMany(currRow => currRow)
                              .Aggregate(1, (current, currByte) => current * 5 + currByte);
    }

    public static bool operator ==(BinaryOperation lhs, BinaryOperation rhs)
    {
      if (ReferenceEquals(null, lhs) ||
          ReferenceEquals(null, rhs))
      {
        return false;
      }

      return (0 == lhs.CompareTo(rhs));
    }

    public static bool operator !=(BinaryOperation lhs, BinaryOperation rhs)
    {
      if (ReferenceEquals(null, lhs) ||
          ReferenceEquals(null, rhs))
      {
        return false;
      }

      return (0 != lhs.CompareTo(rhs));
    }

    #endregion EqualityOperators
  }
}
4

1 回答 1

4

在 ==、CompareTo()== 0 和 Equals() 之间出现这种分歧的后果是什么?

将来有人看你的代码会很讨厌你。

或者:是否有描述哪个扩展使用哪个接口(IEquitable 或 IComparable)的 linq 扩展方法列表?

我想你已经自己找到了大部分。一个好的经验法则是,通常哪个 LINQ 函数使用哪个接口并没有什么令人惊讶的(毫不奇怪是良好设计的特征之一 - 与您的不同)。例如:很明显,要对元素进行排序,有必要知道元素应该按哪个特定顺序排列,仅靠相等/不等式是不够的。BinarySearch在搜索过程中还需要知道“要走哪条路”——如果元素大于当前元素,它会递归到排序数组的上部,如果更小,它就会进入下部。再次:显然它需要IComparable. 就足够Distinct EqualsGetHashCode- 不需要排序来确定一组独特的元素。等等。

于 2013-12-09T20:27:47.963 回答