2009-07-30 12 views
6

Mam następujący sposób:Jak uzyskać kompilator C# do wnioskowania rodzajów ogólnych?

public TResult Get<TGenericType, TResult>() 
          where TGenericType : SomeGenericType<TResult> 
          where TResult : IConvertible { 
    //...code that uses TGenericType... 
    //...code that sets someValue... 
    return (TResult) someValue; 
} 

Teraz użytkownik tej metody używać go tak:

//Notice the duplicate int type specification 
int number = Get<SomeGenericType<int>, int>(); 

Dlaczego muszę określić TResult w metodzie umowach definicja? Kompilator zna już TRESult, ponieważ określiłem go w TGenericType. Idealnie (jeśli kompilator C# był trochę mądrzejszy), moja metoda będzie wyglądać następująco:

public TResult Get<TGenericType>() 
          where TGenericType : SomeGenericType<TResult> 
          where TResult : IConvertible { 
    //...code that uses TGenericType... 
    //...code that sets someValue... 
    return (TResult) someValue; 
} 

więc użytkownik może po prostu używać go tak:

//Much cleaner 
int number = Get<SomeGenericType<int>>(); 

Czy istnieje sposób, aby zrobić co chcę robić?

+0

Myślę, że usunięcie niektórych kwalifikatorów, takich jak * głupi * z opisu pytania, pomoże. – EFraim

+0

To jest kompilator, który jest głupi, prawda? ;) Usunąłem obcy komentarz. Bez tego właściwie jest to rozsądne pytanie. –

+0

Ponieważ otrzymałeś odpowiedź, że nie ma sposobu, aby użyć tylko niektórych parametrów typu, być może powinieneś przeformułować swoje pytanie pod kątem tego, co chcesz osiągnąć. W obecnej formie, twoje pytanie brzmi: "w jaki sposób mogę skompilować kompilator C#, który narusza definicję języka C#?" Jako taki powinien być zamknięty jako "nie jest to prawdziwe pytanie". –

Odpowiedz

8

Specyfikacja C# nie pozwala na wnioskowanie połowy argumentów typu. Powinieneś pozwolić kompilatorowi wywnioskować wszystkie argumenty typu (co nie zawsze ma zastosowanie, jak w twoim przypadku) lub ręcznie określić wszystkie.

UPDATE (Odpowiedź): Chociaż nie jestem w zespole C#, aby dać bezwzględną odpowiedź na pytanie, moje spekulacje, że złożoność rozdzielczości przeciążeniowym (który jest już oszałamiające, Ty wiesz że jeśli przeczytasz tę sekcję specyfikacji C#), znacznie wzrośnie, jeśli chcesz, aby połowa typów została wywnioskowana, a połowa nie (zwłaszcza biorąc pod uwagę fakt, że możesz przeciążać metody wyłącznie liczbą ogólnych argumentów).

+0

Ale dlaczego określili to w specyfikacji C#? To nie jest tak, że jest w tym coś niebezpiecznego. –

+0

Sprawdź niektóre z reguł C++, w tym częściową specjalizację szablonów i działanie kreatorów dostępu. Zwykle wszystko działa sprawnie, ale są tu i tam przeczucia. Ponieważ jedną z idei Java i C# było uniknięcie komplikacji C++, przyjmując za to trochę niedogodności, jest to dokładnie zgodne. –

1

To zależy ...

Jeśli jesteś po prostu używając SomeGenericType<TResult>, można zrobić:

public TResult Get<TResult>() where TResult : IConvertible { 
    SomeGenericType<TResult> myInstance = ... 
    //...code that sets someValue... 
    return (TResult) someValue; 
} 

Nie zawsze jest sposób, aby umieścić tam pierwszego typu, w tym przypadku . Ponieważ Twój przykład nie przekazuje jawnie parametru jako SomeGenericType<TResult>, sugeruje, że byłoby to możliwe.

W przeciwnym razie należy całkowicie określić wszystkie ogólne argumenty. Niestety, tak właśnie jest w C#.

+0

Oczywiście, ale potrzebuję użyć SomeGenericType w metodzie. Zaktualizuję mój przykładowy kod, aby to wyjaśnić. –

+0

Tak, ale spójrz na mój kod - o ile nie zostanie przekazany jako parametr do metody, możesz użyć metody SomeGenericType w metodzie (np. Jeśli ją skonstruujesz w metodzie). Ponieważ znasz TResult, działa to dobrze. Jak już powiedziałem - może w niektórych przypadkach zadziałać ... –

+0

Przepraszam, chodzi mi o to, że muszę użyć TGenericType (zobacz mój zaktualizowany przykładowy kod). –