Словарь с ключом Func
Мне интересно, является ли это разумным выбором ключа для словаря? Я хочу использовать выражение как ключ в словаре, например:
var map3 = new Dictionary<Func<int, bool>, int>();
map3.Add((x) => x % 2 == 0, 1);
map3.Add((x) => x % 10 == 0, 2);
// ...
var key = map3.Keys.SingleOrDefault(f => f(2));
// key = (x) => x % 2
// map3[key] = 1
Идея заключается в том, что это более чистый способ, чем наличие больших if-else или операторов switch.
Это имеет смысл? Это будет работать? Есть ли более простой способ?
Ответы
Ответ 1
Нет, С# создает новый экземпляр делегата всякий раз, когда используется лямбда, поэтому вы не сможете использовать его в качестве согласованного ключа. Пример:
Func<int, int> f = x => x*x + 1;
Func<int, int> g = x => x*x + 1;
Console.WriteLine(f.Equals(g)); // prints False
Это сделало бы использование неудобным в качестве словарного ключа, если бы у вас не было другого способа всегда получать один и тот же экземпляр.
Edit:
Эрик Lippert ответ здесь указывает, что компилятору разрешено обнаруживать, что лямбды одинаковы (хотя обычно это не так). В любом случае лямбда/делегат делает плохой выбор для ключа.
Ответ 2
Учитывая способ использования вашей карты, вам будет лучше с List<Tuple<Func<int,bool>,int>>
, потому что порядок проверки lambdas больше не будет произвольным, как в словаре с хэш-настройкой. Этот подход также позволяет пропустить шаг поиска:
var map3 = new List<Tuple<Func<int,bool>,int>> {
new Tuple<Func<int,bool>,int>((x) => x % 2 == 0, 1)
, new Tuple<Func<int,bool>,int>((x) => x % 10 == 0, 2)
};
var t = map3.SingleOrDefault(t => t.Item1(2));
if (t != null) {
var v = t.Item2;
}
Ответ 3
Переписать ответ @dasblinkenlight с последним синтаксисом:
void Main()
{
var map3 = new List<(Func<int, bool> Key, int Value)> {
(Key: (x) => x * 2 == 4, Value: 1),
(Key: (x) => x * 10 == 100, Value: 2)
};
var result = map3.SingleOrDefault(x => x.Key(10));
Console.WriteLine(result.Value);
}
Когда Key
оценивает Func, которого нет в List
, SingleOrDefault
возвращает элемент с нулевым ключом и значением 0.
Key
и Value
выше предназначены для удобства чтения, их можно удалить, и в этом случае result.Intem2
будет выдавать результат