Словарь с ключом 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 будет выдавать результат