2012-11-16 16 views
8

Zastanawiam się, czy jest to rozsądny wybór klucza do słownika? Co chcę zrobić, to użyć wyrażenia jako klucz w słowniku, coś takiego:Słownik z Func jako kluczem

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 

Pomysł jest to przejrzysty sposób niż posiadające duże if-else lub switch.

Czy to ma sens? Czy to zadziała? Czy istnieje prostszy sposób?

+1

Jednym słowem; Nie. Często jest to właściwa wartość, ale jako klucz unikam jej. – Servy

+2

.. to by mi poszło w utrzymaniu, że ... –

Odpowiedz

7

Nie, C# tworzy nową instancję delegata, gdy używana jest funkcja lambda, więc nie można jej używać jako spójnego klucza. Przykład:

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

Byłoby następnie dokonać Wykorzystanie niezręczne jako klucz słowniku chyba miałeś jakiś inny sposób, aby zawsze uzyskać tę samą instancję.

Edit:

Eric Lippert za odpowiedź here wskazuje, że kompilator jest dozwolone do wykrywania lambdas są takie same (choć zazwyczaj nie robi). Tak czy inaczej lambda/delegat robi zły wybór na klucz.

+0

ok dzięki, to wyczyściło to w górę – user380689

6

Biorąc pod uwagę sposób, w jaki korzystasz z mapy, lepiej będzie z List<Tuple<Func<int,bool>,int>>, ponieważ kolejność sprawdzania lambdas nie będzie już arbitralna, jak w słowniku opartym na haszyszu. Ta metoda pozwala także pominąć krok wyszukiwania:

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; 
} 
+0

hmm, to ciekawe, muszę go jeszcze bardziej przestudiować. Dziękuję Ci. – user380689