Cannot implicitly convert type 'Int' to 'T'
C#GenericsC# Problem Overview
I can call Get<int>(Stat);
or Get<string>(Name);
But when compiling I get:
> Cannot implicitly convert type 'int' to 'T'
and the same thing for 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;
}
}
C# Solutions
Solution 1 - C#
You should be able to just use Convert.ChangeType()
instead of your custom code:
public T Get<T>(Stats type) where T : IConvertible
{
return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}
Solution 2 - C#
Any time you find yourself switching on a type in a generic you are almost certainly doing something wrong. Generics should be generic; they should operate identically completely independent of the type.
If T can only be int or string then don't write your code this way at all in the first place. Write two methods, one that returns an int and one that returns a string.
Solution 3 - C#
Actually, you can just convert it to object
and then to T
.
T var = (T)(object)42;
An example for 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
}
}
Sometimes, this behavior is desirable. For instance, when implementing or overriding a generic method from a base class or interface and you want to add some different functionalities based on the T
type.
Solution 4 - C#
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;
}
}
Solution 5 - C#
ChangeType
is probably your best option. My solution is similar to the one provided by BrokenGlass with a bit of try catch logic.
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;
}
Solution 6 - C#
Try this:
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];
}
}
Solution 7 - C#
Considering @BrokenGlass logic (Convert.ChangeType
) does not support for GUID type.
public T Get<T>(Stats type) where T : IConvertible
{
return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}
Error: Invalid cast from 'System.String' to 'System.Guid'.
Instead, use below logic using TypeDescriptor.GetConverter
by adding System.ComponentModel
namespace.
public T Get<T>(Stats type) where T : IConvertible
{
(T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(PlayerStats[type])
}
Read this.
Solution 8 - C#
It looks like you need a TypeConverter
, see this blog entry.