Расширение File Comparer, метод GetHashCode - PullRequest
0 голосов
/ 30 мая 2020

Я пытаюсь расширить File Comparer, чтобы вычесть root путей из пути к сравниваемым файлам. Проблема в методе GetHashCode(), поскольку у меня есть два разных пути root (root_a и root_b). Как правильно реализовать, чтобы соответствующие root патчей были назначены правильному файлу?

class FileCompare : System.Collections.Generic.IEqualityComparer<System.IO.FileInfo>
{
    string m_root_a;
    string m_root_b;
    public FileCompare() { }
    public FileCompare(string root_a, string root_b) 
    { 
        m_root_a = root_a; 
        m_root_b = root_b; 
    }

    public bool Equals(System.IO.FileInfo f1, System.IO.FileInfo f2)
    {
        return (f1.FullName.Substring(m_root_a.Length) == 
            f2.FullName.Substring(m_root_b.Length) && 
            f1.Length == f2.Length);
    }

    public int GetHashCode(System.IO.FileInfo fi)
    {
        string s = $"{fi.FullName.Substring(m_root_a.Length)}{fi.Length}";
        return s.GetHashCode();
    }
}

Код для тестирования компаратора:

System.IO.DirectoryInfo dir1 = new System.IO.DirectoryInfo("C:\\Dir Compare Tmp\\dir1\\");
System.IO.DirectoryInfo dir2 = new System.IO.DirectoryInfo("C:\\Dir Compare Tmp\\dir2\\");

IEnumerable<System.IO.FileInfo> list1 = dir1.GetFiles("*.*", 
    System.IO.SearchOption.AllDirectories);
IEnumerable<System.IO.FileInfo> list2 = dir2.GetFiles("*.*", 
    System.IO.SearchOption.AllDirectories);
FileCompare myFileCompare = new FileCompare("C:\\Dir Compare Tmp\\dir1\\", 
    "C:\\Dir Compare Tmp\\dir2\\");

bool areIdentical = list1.SequenceEqual(list2, myFileCompare);

List<string> commonFilesList = new List<string>();
List<string> files1OnlyList = new List<string>();
List<string> files2OnlyList = new List<string>();

var queryCommonFiles = list1.Intersect(list2, myFileCompare);
var queryList1Only = (from file in list1 select file).Except(list2, myFileCompare);
var queryList2Only = (from file in list2 select file).Except(list1, myFileCompare);

foreach (var v in queryCommonFiles)
    commonFilesList.Add(v.FullName);

foreach (var v in queryList1Only)
    files1OnlyList.Add(v.FullName);

foreach (var v in queryList2Only)
    files2OnlyList.Add(v.FullName);

Обновление: К сожалению, код не работает должным образом когда у меня разные длины root путей, например, второй путь C:\\Dir Compare Tmp\\dir2 - Copy\\. У меня нет файлов в commonFilesList (с использованием реализации GetHashCode из ответа; функция Equals не работает). Что было бы для этого решения, или мне следует использовать другой подход для сравнения файлов? Это будет использоваться для сравнения большого количества файлов, поэтому важна задержка кода.

1 Ответ

1 голос
/ 30 мая 2020

Поскольку ваш компаратор уже сохраняет оба пути root и ожидается, что только файлы из этих путей будут переданы методу GetHashCode, я надеюсь, что следующая реализация сделает то, что вы хотите достичь. *


Обновление

На основе комментария от @ Rufus

согласно указанной статье в CA1065: не создавать исключения в неожиданных местах в нем указано, что

методы GetHashCode: Object.GetHashCode и IEqualityComparer.GetHashCode(Object) метод «обычно» не должен генерировать исключения.

  1. GetHashCode всегда должен возвращать значение. В противном случае вы можете потерять элементы в таблице ha sh.
  2. Версии GetHashCode, которые принимают аргумент, могут вызывать исключение ArgumentException. Однако Object.GetHashCode никогда не должен вызывать исключения.

НО

Если я я разрабатываю это приложение и убедитесь, что сравниваются только файлы из указанных каталогов, я бы определенно выбросил исключение.

  • Если разработчик сознательно или неосознанно сравнивает файлы из двух разных папки, одна или обе из которых не использовались, почему инициализация объекта, то сравнение файлов полностью недопустимо.
  • Кроме того, метод GetHashCode возвращает int, а Windows позволяет uint (4x10 ^ 10) количество файлов. И если кто-то (кто знает?) Попытается взломать код, обязательно произойдет столкновение ha sh и, следовательно, ложные совпадения; и я не люблю рисковать.

Вместо этого я буду в порядке с потерей Hashtable, показывая сообщение об ошибке пользователю / разработчику и прося его / ее начать заново.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...