2013-07-16 11 views
5

Nie jestem do końca pewny, jak sprawić, aby to pytanie było zrozumiałe, ale wysłuchaj mnie i mam nadzieję, że zrozumiesz mój problem, kiedy dotrzemy do końca (przynajmniej jest on łatwy do odtworzenia).Dlaczego wnioskowanie o typie metody nie pozwala określić parametru typu?

Próbuję wywołać metodę używaną do sprawdzania poprawności wyników w jednostkach testowych. To ma następujący podpis:

void AssertPropertyValues<TEnumerable, TElement, TProperty>(
    TEnumerable enumerable, 
    Func<TElement, TProperty> propertyPointer, 
    params TProperty[] expectedValues) 
    where TEnumerable : System.Collections.Generic.IList<TElement> 

co to oznacza to, że ma następujące wejścia

  1. Każdy obiekt, który jest przeliczalny, a zawiera obiekty tego samego typu co intput za 2).
  2. Func (zwykle enkapsulujące wyrażenia lambda), które pobiera obiekt tego samego typu co "zawartość" 1) i zwraca obiekt tego samego typu co Typ zawartości tablicy podanej w 3).
  3. Tablica obiektów tego samego typu, co wyjściowa funkcja Func in 2).

więc rzeczywiste wykonanie tej metody może wyglądać następująco:

AssertPropertyValues(
    item.ItemGroups, 
    itemGroup => itemGroup.Name, 
    "Name1", "Name2", "Name3"); 

Przynajmniej tak jest, jak chciałbym to wyglądać, ale biegnę do znanego błędu kompilatora: "Argumentów typu dla metody" X "nie da się wywnioskować z użycia". I tego właśnie nie rozumiem. Powinien mieć wszystkie potrzebne informacje, o ile widzę, a może jest to kolejna wersja problemu "Kowariancji i Kontrawariancji"?

Więc teraz jestem zmuszony robić to tak zamiast:

AssertPropertyValues(
    item.ItemGroups, 
    (ItemGroup itemGroup) => itemGroup.Name, 
    "Name1", "Name2", "Name3"); 

Czy ktoś może wskazać, dlaczego ten scenariusz nie można wywnioskować przez kompilator?

+1

Czy próbowałeś użyć 'IEnumerable ' lub sth podobnie zamiast 'TEnumerable'? w zasadzie parametr 'propertyPointer' powinien być taki sam, jak predykat, np. w metodzie' Enumerable.Select'-extension (a więc i całej konstrukcji), której typem jest 'item.ItemGroups' (dowolna missmatch, która czyni podpis jawny jest obowiązkowy?)? w przeciwnym razie nie napotkasz problemu, przed którym stoisz ... –

+0

Naprawiłem formatowanie próbek kodu tak, aby były sensowne i zmieniły nazwę na pytanie; to nie ma nic wspólnego z lambdą. –

+0

@AndreasNiedermair Mój problem wynika z tego, że początkowo miałem to ograniczenie w wielu miejscach, i w niektórych miejscach używałem ich jako typów zwrotów, a zatem nie mogłem "zrobić" tylko z interfejsami. Już nie w przypadku wypróbowywania rozwiązania EricLipperta. –

Odpowiedz

24

Twój problem jest spowodowany tym, że ograniczenia nie są uważane za część podpisu i nigdy nie są używane do dokonywania dedukcji podczas wnioskowania o typ. Spodziewamy się, że odpowiedź będzie następująca:

  • TEnumerable jest określona przez przyjęcie typu pierwszego argumentu.
  • TElement jest określana poprzez informacje IList<T> realizacji od TElement
  • TProperty zależy od rodzaju ciała lambda

Ale nigdy C# powoduje, że drugi krok, ponieważ to wymaga uznawania za równoważne informacji z przymusu . Jak zauważysz, jeśli podasz tę informację w lambda, kompilator dokonuje dedukcji na podstawie formalnego parametru parametru.

Na szczęście twoje ograniczenie jest zupełnie niepotrzebne. Przepisz metodę mieć prostszą podpis, który nie posiada ograniczenia:

void AssertPropertyValues<TElement, TProperty>(
    IList<TElement> sequence, 
    Func<TElement, TProperty> projection, 
    params TProperty[] expectedValues) 

i teraz powinno być w porządku.

I podczas gdy jesteś na tym, powinieneś prawdopodobnie uprościć to do IEnumerable<TElement>, chyba że z jakiegoś powodu potrzebujesz IList<T>.

+0

Ah, faktycznie myślałem, że ograniczenia zostały użyte. Szkoda, że ​​tak nie jest. Jak wskazałem w komentarzu do mojego pytania, nie mogłem tego uprościć na samym początku, z powodu zależności od innych metod, które wymagały podpisu dla typów zwrotu. Po pewnym refaktoryzacji twoje rozwiązanie zadziałało jednak dla mnie. Dzięki! :) (i tak, potrzebuję IList ale dziękuję za wskazanie to w każdym razie) –

Powiązane problemy