Есть некий метод, пусть public static bool IsNewFileActual(sting oldFile, string newFile, ComparsionFlags flags) сравнивающий 2 файла по набору критериев. Сами критерии, для наглядности, например, такие: сравнение по дате последней записи в файл, версия файла, MD5-хэш, размер файла.
В зависимости от некоторых условий, должна формироваться переменная flags, которая будет задавать флаги для критериев проверки (например, флаг проверки по номеру версии будет справедлив для *.EXE и *.DLL, а вот для *.PNG или *.HTML он не нужен).
В паскале (Delphi), я бы работал примерно так:
type
TComparsionFlags = set of (cfDate, cfVersion, cfHash, cfSize);
var
CF : TComparsionFlags;
...
CF := [];
CF := CF + [cfVersion];
...
СF := CF + [cfHash, cfSize];
...
CF := CF - [cfDate];
...
if (cfDate in CF) then
begin
...
end;
Иными словами, описал бы множество с возможными флагами, и использовал бы средства языка для достижения своих целей.
Насколько я знаю, аналога паскалевских множеств в C# в чистом виде нет, и в качестве замены можно использовать enum, что я и делаю:
[Flags]
public enum ComparsionFlags : byte
{
cfVersion = 1,
cfSize = 2,
cfDate = 4,
cfHash = 8,
}
После чего перед вызовом метода IsNewFileActual объявляю переменную ComparsionFlags flags и далее задаю флаги так:
flags = ComparsionFlags.cfSize | ComparsionFlags.cfDate | ComparsionFlags.cfHash;
Как по мне, так это не очень удобно (по меньшей мере, как минимум, не лаконично), как для задания самой переменной flags, так и для проверок значений, которые переданы в этой переменной внутрь метода.
Собственно, вопрос и в заголовке, и вот, более детально:
Как наилучшим образом реализовать тип ComparsionFlags для использования переменных данного типа в качестве набора флагов?
Может быть есть альтернативные, более удобные способы выполнить описанную задачу?
Буду признателен за внимание и дельные советы/ответы. Спасибо.
P.S. Думал про List и HashTable, но есть ощущение, что это несколько не то... Например, ничто не мешает добавить в List какой-то флаг n раз, и при удалении этого флага из списка придется просматривать его весь, и удалять все вхождения этого флага (или флагов), т.е. получаем, что нужно довольно много обвязки вокруг списка делать.
Ответ
Использование флагов выглядит достаточно лаконично. Если переписать код с Delphi, получится примерно так:
ComparsionFlags CF = default(ComparsionFlags);
CF = CF | ComparsionFlags.cfVersion;
...
СF = CF | ComparsionFlags.cfHash | ComparsionFlags.cfSize;
...
CF = CF & ~ComparsionFlags.cfDate;
...
if (CF.HasFlag(ComparsionFlags.cfDate)) {
...
}
Если использовать using static, то имя enum можно опускать:
using static ComparsionFlags;
...
ComparsionFlags CF = default(ComparsionFlags);
CF |= cfVersion;
...
СF |= cfHash | cfSize;
...
CF &= ~cfDate;
...
if (CF.HasFlag(cfDate)) {
...
}
В противовес, можно использовать класс HashSet, как указано в соседнем ответе:
HashSet flags = new HashSet();
CF.Add(ComparsionFlags.cfVersion);
...
СF.UnionWith(new[]{ComparsionFlags.cfHash,ComparsionFlags.cfSize});
...
CF.Remove(ComparsionFlags.cfDate);
...
if (CF.Contains(ComparsionFlags.cfDate)) {
...
}
Как можно заметить, в этом случае не обязательно делать значения enum флагами, то есть значения могут идти и подряд: 1,2,3..., а не 1,2,4...