Waarde van type ‘T’ kan niet worden geconverteerd naar

Dit is waarschijnlijk een beginnersvraag, maar Google heeft verrassend genoeg geen antwoord gegeven.

Ik heb deze nogal kunstmatige methode

T HowToCast<T>(T t)
{
    if (typeof(T) == typeof(string))
    {
        T newT1 = "some text";
        T newT2 = (string)t;
    }
    return t;
}

Vanuit een C++ achtergrond verwachtte ik dat dit zou werken. Het compileert echter niet met “Kan type ‘T’ niet impliciet converteren naar string” en “Kan type ‘T’ niet converteren naar string” voor beide bovenstaande opdrachten.

Ik doe ofwel iets conceptueel verkeerd of heb gewoon de verkeerde syntaxis. Help me dit op te lossen.

Bedankt!


Antwoord 1, autoriteit 100%

Ook al zit het in een if-blok, de compiler weet niet dat Tstringis.
Daarom kun je niet casten. (Om dezelfde reden dat je DateTimeniet kunt casten naar string)

Je moet casten naar object(waarnaar elke Tkan casten), en van daaruit naar string(sinds objectkan worden gecast naar string).
Bijvoorbeeld:

T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;

Antwoord 2, autoriteit 4%

Beide regels hebben hetzelfde probleem

T newT1 = "some text";
T newT2 = (string)t;

De compiler weet niet dat T een string is en kan dus ook niet weten hoe hij die moet toewijzen.
Maar aangezien je het hebt gecontroleerd, kun je het gewoon forceren met

T newT1 = "some text" as T;
T newT2 = t; 

je hoeft de t niet te casten omdat het al een tekenreeks is, je moet ook de beperking toevoegen

where T : class

Antwoord 3, autoriteit 2%

Ik ken soortgelijke code die de OP in deze vraag heeft gepost van generieke parsers. Vanuit prestatieperspectief moet u Unsafe.As<TFrom, TResult>(ref TFrom source)gebruiken, die u kunt vinden in de System.Runtime.CompilerServices.UnsafeNuGet-pakket. Het vermijdt boksen voor waardetypen in deze scenario’s. Ik denk ook dat Unsafe.Asresulteert in minder machinecode die door het JIT wordt geproduceerd dan tweemaal casten (met behulp van (TResult) (object) actualString), maar ik heb het niet gecontroleerd dat uit.

public TResult ParseSomething<TResult>(ParseContext context)
{
    if (typeof(TResult) == typeof(string))
    {
        var token = context.ParseNextToken();
        string parsedString = token.ParseToDotnetString();
        return Unsafe.As<string, TResult>(ref parsedString);
    }
    else if (typeof(TResult) == typeof(int))
    {
        var token = context.ParseNextToken();
        int parsedInt32 = token.ParseToDotnetInt32();
        // This will not box which might be critical to performance
        return Unsafe.As<int, TResult>(ref parsedInt32); 
    }
    // other cases omitted for brevity's sake
}

Unsafe.Aszal worden vervangen door de JIT met efficiënte machinecode-instructies, zoals je kunt zien in de officiële CoreFX-repo:

Broncode van Unsafe.As


Antwoord 4

Als je zoekt naar expliciete typen, waarom declareer je die variabelen dan als T‘s?

T HowToCast<T>(T t)
{
    if (typeof(T) == typeof(string))
    {
        var newT1 = "some text";
        var newT2 = t;  //this builds but I'm not sure what it does under the hood.
        var newT3 = t.ToString();  //for sure the string you want.
    }
    return t;
}

Antwoord 5

Je krijgt deze foutmelding ook als je een generieke declaratie hebt voor zowel je klasse als je methode. De onderstaande code geeft bijvoorbeeld deze compileerfout.

public class Foo <T> {
    T var;
    public <T> void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
        this.var = cls.newInstance();
    }
}

Deze code compileert wel (noot T verwijderd uit methodedeclaratie):

public class Foo <T> {
    T var;
    public void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
        this.var = cls.newInstance();
    }
}

Antwoord 6

Verander deze regel:

if (typeof(T) == typeof(string))

Voor deze regel:

if (t.GetType() == typeof(string))

Other episodes