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;
}
}
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.
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));
}
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;
}
}
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;
}
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];
}
}
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 .
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
.
Il semble que vous ayez besoin d'un TypeConverter
, voir cette entrée de blog .
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;
}
}