web-dev-qa-db-fra.com

Impossible de convertir implicitement le type 'Int' en 'T'

Je peux appeler Get<int>(Stat); ou Get<string>(Name);

Mais lors de la compilation, je reçois:

Impossible de convertir implicitement le type 'int' en 'T'

et la même chose pour string.

public T Get<T>(Stats type) where T : IConvertible
{
    if (typeof(T) == typeof(int))
    {
        int t = Convert.ToInt16(PlayerStats[type]);
        return t;
    }
    if (typeof(T) == typeof(string))
    {
        string t = PlayerStats[type].ToString();
        return t;
    }
}
74
David W

Chaque fois que vous vous retrouvez à changer de type dans un générique vous faites certainement quelque chose de mal. Les génériques doivent être generic ; ils doivent fonctionner de manière identique , indépendamment du type .

Si T ne peut être qu'un entier ou une chaîne, n'écrivez pas votre code de cette façon. Écrivez deux méthodes, une qui retourne un int et une qui retourne une chaîne.

119
Eric Lippert

Vous devriez pouvoir simplement utiliser Convert.ChangeType() au lieu de votre code personnalisé:

public T Get<T>(Stats type) where T : IConvertible
{
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}
121
BrokenGlass
public T Get<T>(Stats type ) where T : IConvertible
{
    if (typeof(T) == typeof(int))
    {
        int t = Convert.ToInt16(PlayerStats[type]);
        return (T)t;
    }
    if (typeof(T) == typeof(string))
    {
        string t = PlayerStats[type].ToString();
        return (T)t;
    }
}
10
Reza ArabQaeni

ChangeType est probablement votre meilleure option. Ma solution est similaire à celle fournie par BrokenGlass avec un peu de logique try catch.

static void Main(string[] args)
{
    object number = "1";
    bool hasConverted;
    var convertedValue = DoConvert<int>(number, out hasConverted);

    Console.WriteLine(hasConverted);
    Console.WriteLine(convertedValue);
}

public static TConvertType DoConvert<TConvertType>(object convertValue, out bool hasConverted)
{
    hasConverted = false;
    var converted = default(TConvertType);
    try
    {
        converted = (TConvertType) 
            Convert.ChangeType(convertValue, typeof(TConvertType));
        hasConverted = true;
    }
    catch (InvalidCastException)
    {
    }
    catch (ArgumentNullException)
    {
    }
    catch (FormatException)
    {
    }
    catch (OverflowException)
    {
    }

    return converted;
}
8
Michael Ciba

Essaye ça:

public T Get<T>(Stats type ) where T : IConvertible
{
    if (typeof(T) == typeof(int))
    {
        return (T)(object)Convert.ToInt16(PlayerStats[type]);

    }
    if (typeof(T) == typeof(string))
    {

        return (T)(object)PlayerStats[type];
    }
}
6
Michael Kalinovich

Considérant la logique de @BrokenGlass (Convert.ChangeType) ne prend pas en charge le type GUID.

public T Get<T>(Stats type) where T : IConvertible
{
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}

Erreur : transtypage non valide de 'System.String' à 'System.Guid'.

Utilisez plutôt la logique ci-dessous en utilisant TypeDescriptor.GetConverter en ajoutant System.ComponentModel espace de noms.

public T Get<T>(Stats type) where T : IConvertible
{
    (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(PlayerStats[type])
}

Lire ceci .

4

En fait, vous pouvez simplement le convertir en object puis en T.

T var = (T)(object)42;

Un exemple pour bool:

public class Program
{
    public static T Foo<T>()
    {
        if(typeof(T) == typeof(bool)) {
            return (T)(object)true;
        }

        return default(T);
    }

    public static void Main()
    {
        bool boolValue = Foo<bool>(); // == true
        string stringValue = Foo<string>(); // == null
    }
}

Parfois, ce comportement est souhaitable. Par exemple, lorsque vous implémentez ou substituez une méthode générique à partir d'une classe ou d'une interface de base et que vous souhaitez ajouter différentes fonctionnalités basées sur le type T.

4
GregaMohorko

Il semble que vous ayez besoin d'un TypeConverter, voir cette entrée de blog .

3
Ian Mercer

Vous pouvez simplement lancer comme ci-dessous,

public T Get<T>(Stats type) where T : IConvertible
{
  if (typeof(T) == typeof(int))
  {
    int t = Convert.ToInt16(PlayerStats[type]);
    return t as T;
  }
 if (typeof(T) == typeof(string))
 {
    string t = PlayerStats[type].ToString();
    return t as T;
 }
}