Pytanie Dlaczego operator potrójny C # nie współpracuje z delegatami?


Podczas rozgałęzienia w celu wybrania funkcji może być użyteczne użycie operatora trójskładnikowego w celu wybrania funkcji, ale jest to niemożliwe. Czemu?

public class Demo {
    protected bool branch;
    protected void demo1 () {}
    protected void demo2 () {}
    public Action DoesntWork() {
        return branch ? demo1 : demo2;
    }
}

Kompilator generuje następujący błąd:

Cannot implicitly convert type `method group' to `System.Action'

14
2017-10-14 19:56


pochodzenie




Odpowiedzi:


Problemem jest demo1 nie jest prostym wyrażeniem, jest to metoda. Metody można przesłonić, więc tak naprawdę nie jest jeden metoda, to jest grupa metod. Rozważmy następujący przykład:

public class Demo {
    protected bool branch;
    protected void demo1 (int) {}
    protected void demo1 () {}
    protected void demo2 () {}
    public Action DoesntWork() {
        return branch ? demo1 : demo2; //Error
        return demo1; //ok
    }
}

Teraz, demo1 jest przeciążony, więc która z dwóch wersji powinna być użyta? Odpowiedź jest taka, że ​​przeciążoną funkcję wybiera się za pomocą kontekstu, w którym funkcja jest używana.

w return demo1 to oczywiste, że oczekuje Action.

Ale w return branch? demo1 : demo2; kontekst nie jest taki łatwy. Operator trójskładnikowy najpierw próbuje dopasować typ demo1 z tym z demo2, ale to jest kolejne grupa metod więc nie ma tam pomocy. Kompilator nie wykracza poza i nie powiedzie się.

Rozwiązaniem jest wyjaśnienie typu oczekiwanego od grupy metod:

return branch? new Action(demo1) : demo2;

return branch? (Action)demo1 : demo2;

Action d1 = demo1;
return branch? d1 : demo2;

17
2017-10-14 20:03



+1 za wyjaśnienie, dlaczego wnioskowanie typu nie powiedzie się, i że zamiast tego możesz użyć rzutowania new. - Robert Harvey♦


Musisz jawnie utworzyć delegata odpowiedniego typu. Normalnie możesz po prostu użyć demo1 odnosić się do a System.Action, ale to tylko dlatego, że kompilator może wywnioskować typ na podstawie użycia i utworzy dla ciebie delegata. W tym przypadku kompilator nie wie, że twoja metoda powinna zostać przekonwertowana na System.Action gdy jest używany w ramach operatora trójskładnikowego.

Jeśli dostarczysz to sobie nawet dla jednego z argumentów, zadziała:

public Action DoesWork() 
{
    return branch ? demo1 : new Action(demo2);
}

Ponieważ to powraca new Action jednoznacznie dla jednego argumentu kompilator może wywnioskować, że drugi powinien zostać przekonwertowany odpowiednio do a System.Actioni zostanie skompilowane pomyślnie.


6
2017-10-14 19:59