Dictionary with Func as key
Asked Answered
D

3

11

I am wondering if this is a sane choice of key for a dictionary? What I want to do is use an expression as the key in a dictionary, something like:

    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

The idea being this is a cleaner way than having big if-else or switch statements.

Does this make sense? Will it work? Is there an simpler way?

Downwind answered 16/11, 2012 at 2:15 Comment(2)
In a word; no. It's often an appropriate value, but as a key I'd avoid it.Afterclap
..that would do my head in maintaining that..Wiegand
G
8

No, C# constructs a new delegate instance whenever a lambda is used so you wouldn't be able to use it as a consistent key. Example:

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

This would then make usage awkward as a dictionary key unless you had some other way to always obtain the same instance.

Edit:

Eric Lippert's answer here indicates that the compiler is allowed to detect the lambdas are the same (although it typically does not). Either way a lambda/delegate makes a poor choice for a key.

Goodkin answered 16/11, 2012 at 2:27 Comment(0)
W
9

Considering the way that you use your map, you will be better off with a List<Tuple<Func<int,bool>,int>>, because the order of checking the lambdas will no longer be arbitrary, as in a hash-based dictionary. This approach also lets you skip the lookup step:

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;
}
Wet answered 16/11, 2012 at 2:28 Comment(0)
G
8

No, C# constructs a new delegate instance whenever a lambda is used so you wouldn't be able to use it as a consistent key. Example:

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

This would then make usage awkward as a dictionary key unless you had some other way to always obtain the same instance.

Edit:

Eric Lippert's answer here indicates that the compiler is allowed to detect the lambdas are the same (although it typically does not). Either way a lambda/delegate makes a poor choice for a key.

Goodkin answered 16/11, 2012 at 2:27 Comment(0)
O
1

Rewriting @dasblinkenlight's answer with latest syntax:

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);
}

When Key evaluates to a Func which is not there on the List SingleOrDefault returns an element with key null and value 0.

Key and Value above are for readability, they can be removed and in that case result.Intem2 will produce output

Operose answered 22/8, 2019 at 4:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.