Словарь с 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.

Имеет ли это смысл? Это будет работать? Есть ли более простой способ?


person user380689    schedule 16.11.2012    source источник
comment
Одним словом; нет. Часто это подходящее значение, но в качестве ключа я бы его избегал.   -  person Servy    schedule 16.11.2012
comment
..это бы сломало мне голову, поддерживая это ..   -  person Simon Whitehead    schedule 16.11.2012


Ответы (3)


Нет, C# создает новый экземпляр делегата всякий раз, когда используется лямбда, поэтому вы не сможете использовать его в качестве согласованного ключа. Пример:

        Func<int, int> f = x => x*x + 1;
        Func<int, int> g = x => x*x + 1;
        Console.WriteLine(f.Equals(g)); // prints False

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

Редактировать:

Ответ Эрика Липперта здесь указывает, что компилятору разрешено определять, что лямбда-выражения одинаковы (хотя обычно это не так). В любом случае лямбда/делегат делает плохой выбор для ключа.

person Mike Zboray    schedule 16.11.2012

Учитывая то, как вы используете свою карту, вам будет лучше использовать List<Tuple<Func<int,bool>,int>>, потому что порядок проверки лямбда-выражений больше не будет произвольным, как в словаре на основе хэшей. Этот подход также позволяет пропустить шаг поиска:

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;
}
person Sergey Kalinichenko    schedule 16.11.2012

Переписывая ответ @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 будет производить вывод

person Amit    schedule 22.08.2019