Я хочу иметь метод расширения “Equals” между 2-байтовыми массивами
-
20-08-2019 - |
Вопрос
Я делаю несколько сравнений byte[].
Я пробовал == но это точно так же, как базовые значения, которые:
byte[] a = {1,2,3};
byte[] b = {1,2,3};
bool equals = a == b; //false
equals = a.Equals(b); //false
Я попытался добавить метод расширения, но поскольку перегруженный базовый класс Equals принимает те же аргументы, он переходит к базовому методу, а не к расширению, могу ли я в любом случае использовать расширение Equals (без изменения его имени ...) или (что еще лучше) использовать оператор ==?
Вот что мне на самом деле нужно сравнить:
public static bool ContentEquals(this byte[] array, byte[] bytes)
{
if (array == null || bytes == null) throw new ArgumentNullException();
if( array.Length != bytes.Length) return false;
for (int i = 0; i < array.Length; i++)
if (array[i] != bytes[i]) return false;
return true;
}
Решение
using System.Linq;
byte[] a = {1,2,3};
byte[] b = {1,2,3};
bool same = a.SequenceEqual(b);
Другие советы
Вы, конечно, не можете выполнять перегрузку оператора с помощью методов расширения.Причина, по которой это не работает для Equals
метод заключается в том, что если Любой метод применим без использования методов расширения, этот метод будет выбран еще до того, как методы расширения будут даже рассмотрены.
Даже несмотря на то, что ваш Equals
метод "лучше" с точки зрения преобразования типов аргументов в формальные типы параметров, компилятор всегда предпочитает "обычные" методы.Вам придется присвоить своему методу другое имя.
Однако вы всегда можете использовать Enumerable.SequenceEquals
способ.Я не верю, что это приводит к короткому замыканию проверки длины (хотя это могло бы быть, для ICollection<T>
реализации).Однако вы всегда можете самостоятельно внедрить более эффективную версию.Действительно, если вы просто измените существующую реализацию массива, которая будет вызвана SequenceEquals
или даже ArrayEquals
, это было бы прекрасно:
public static bool ArrayEquals(this byte[] array, byte[] bytes)
{
// I'd personally use braces in all of this, but it's your call
if (array.Length != bytes.Length) return false;
for (int i = 0; i < array.Length; i++)
if (array[i] != bytes[i]) return false;
return true;
}
Обратите внимание, что было бы неплохо сделать его универсальным, но это, безусловно, немного снизило бы производительность, поскольку сравнение не могло быть встроено:
public static bool ArrayEquals<T>(this T[] first, T[] second)
{
// Reference equality and nullity checks for safety and efficiency
if (first == second)
{
return true;
}
if (first == null || second == null)
{
return false;
}
if (first.Length != second.Length)
{
return false;
}
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < first.Length; i++)
{
if (!comparer.Equals(first[i], second[i]))
{
return false;
}
}
return true;
}
Я сделал это с той же целью:
static class Global
{
public static bool ArraysAreEqual(Array arr1, Array arr2)
{
if (arr1.Length != arr2.Length)
return false;
System.Collections.IEnumerator e1 = arr1.GetEnumerator();
System.Collections.IEnumerator e2 = arr2.GetEnumerator();
while(e1.MoveNext() && e2.MoveNext())
{
if(!e1.Current.Equals(e2.Current))
return false;
}
return true;
}
}
но обратите внимание, что .Equals() может даже возвращать false для ссылочных типов, когда они равны (я не проводил тест, но вы можете попробовать с помощью StringBuilder ).В моем конкретном случае у меня есть только простые типы значений