2009-06-23 9 views
9

Próbuję napisać metodę tak:Znam typof (T), ale kompilator nie. Jak naprawić?

public static T Test<T>() 
{ 
    if (typeof(T)==typeof(string)) 
    return "1241"; 

    // do something else 
} 

ale nie może wydawać się, aby dowiedzieć się, jak wyciągnąć go wyłączyć. Chcę zwrócić wartości w zależności od typu T, w którym metoda została wywołana. Muszę zwrócić ciągi znaków, int, niestandardowe klasy, listy itp.

Rzeczywistym przypadkiem jest niestandardowy kod serializacji, w którym kluczowym jest, aby kod deserializacyjny znał typ obiektu, który powinien utworzyć.

Wyjaśnienie: powyższy przykład daje następujący błąd: nie można przekonwertować ciąg do typu T

Idealnym rozwiązaniem byłoby pracować typów wartości i typów referencyjnych, a nie obejmują obojętne parametr dla rozdzielczości przeciążenia.

Zaczynam wątpić, czy to idealne rozwiązanie istnieje.

Dzięki, Lucas

+0

typeof (T) powinien działać. Który komunikat o błędzie jest wystawiany przez kompilator? –

Odpowiedz

13

pośredni oddanych do object nie jest idealna, ale coś takiego powinno wystarczyć:

public static T Test<T>() 
{ 
    if (typeof(T) == typeof(string)) 
     return (T)(object)"1241"; 

    // do something else 
} 
+0

Ah crap, właśnie to powiedziałem! :) – leppie

6

Musisz odrzucić wartość zwracaną do T, np. coś takiego dla typów referencyjnych:

public static T Test<T>() where T : class 
{ 
    if (typeof(T)==typeof(string)) 
    return "1241" as T; 

    return default(T); 
} 
+0

Kompilator mówi: Nie można przekonwertować typu "ciąg" na T –

+0

Przepraszam, zaktualizowałem próbkę. Zwróć uwagę na część "gdzie T: klasa". – M4N

+0

Jedynym problemem jest teraz T musi być klasą, więc nie będzie działać dla int, long, itp. –

5

Strzeż! Poniższe rozwiązanie wykonuje pracę , a nie (weryfikowane przy użyciu kompilatora C# w stylu Mono gmcs).

Należy jednak powinien pracować przez moje czytanie standardu C#, ponieważ rozdzielczość przeciążania powinny faworyzować nie ogólnej wersji metody, gdy to możliwe. Odpowiednia sekcja w ECMA-334 to 25.1.7: "Przeciążenie w klasach ogólnych". Co więcej, Eric Lippert zdaje się tak samo mówić w numerze blog posting.

opinie będą mile widziane: dlaczego to nie działa zgodnie z oczekiwaniami?


Masz niepowiązanych rodzajów i niezwiązane zachowanie: kod ten krzyczy „! użycie przeciążenia

rodzajowych byłoby właściwe dla niespokrewnionych typów, ale identyczna (lub bardzo podobne) zachowanie.

zrobić (kompletny program testowy, aby odtworzyć zachowanie):

using System; 

class TestClass { 
    public static T Test<T>() { 
     return TestWith(default(T)); 
     // do something else 
    } 

    public static string TestWith(string dummy) { 
     // Used only for `string`. 
     return "string"; 
    } 

    public static T TestWith<T>(T dummy) { 
     // Used for everything else. 
     return dummy; 
    } 

    static void Main() { 
     Console.WriteLine("Expected \"0\", got \"{0}\"", Test<int>()); 
     Console.WriteLine("Expected \"string\", got \"{0}\"", Test<string>()); 
    } 
} 

Zestawione z gmcs, Daje:

Expected "0", got "0" 
Expected "string", got "" 

Tutaj parametr służy tylko do dezambiguacji z przeciążonej rozmowy. Nie można użyć jawnych parametrów ogólnych, ponieważ jedna z funkcji (specjalizacja string) nie jest generyczna.

+0

Test nadal wywołuje TestWith zamiast TestWith (ciąg) –

+0

Patrick: cholera. prawdziwe. Byłem pewien, że już to wykorzystałem. Powrót do deski kreślarskiej. –

+0

Niestety, nie rozumiem, na czym polega problem. Czy możesz zapewnić program, który faktycznie kompiluje i pokazuje wyniki, których się nie spodziewasz? –

2

Spróbuj

public static T Test<T>() where T : class 
{ 
    if (typeof(T) == typeof(string)) return "asdf" as T; // do something else 
    // do something else   
} 
+1

Wykonaj twardą obsadę "(T)" zamiast używać "jako T". Następnie możesz usunąć klauzulę where. – Jehof

+0

@Jehof: ale kod nie będzie już kompilowany. Więc nie, nie rób tego. –

+0

@ Konrad. Oczywiście masz rację. To nie działa – Jehof

1

można używać changetype?

public static T Test<T>() 
{ 
    if (typeof(T)==typeof(string)) 
     return (T)Convert.ChangeType("1234", typeof(T), CultureInfo.InvariantCulture); 
    return default(T); 
} 
0

znalazłem rozwiązanie:

public static T Test<T>() 
{ 
    if (typeof(T) == typeof(string)) 
    return (T)(object)"1241"; // this works. 

    // do something else 
} 

Dzięki za wszystkie odpowiedzi .

+0

Proszę, sprawdź odpowiedź Luke'a, wymyślił to samo co Ty –

0
public static T Test<T>() 
{ 
    if (typeof(T)==typeof(string)) 
    return (T)Convert.ChangeType("1241", typeof(T)); 

    return default(T); 
} 

Nie Przetestowałem go chociaż :-)

Powiązane problemy