Generic type conversion FROM string
I am not sure whether I understood your intentions correctly, but let's see if this one helps.
public class TypedProperty<T> : Property where T : IConvertible
{
public T TypedValue
{
get { return (T)Convert.ChangeType(base.Value, typeof(T)); }
set { base.Value = value.ToString();}
}
}
Convert string to generic type c# (Convert string to T)
you can use Convert.ChangeType
T GetValue<T>(string name)
{
string item = getstuff(name);
return (T)Convert.ChangeType(item, typeof(T));
}
if you need to limit input types only for int and DateTime, add condition like below
if (typeof(T) != typeof(int) && typeof(T) != typeof(DateTime))
{
// do something with other types
}
KOTLIN convert string to generic type
You can write generic inline function with reified type parameter:
inline fun <reified T> read() : T {
val value: String = readLine()!!
return when (T::class) {
Int::class -> value.toInt() as T
String::class -> value as T
// add other types here if need
else -> throw IllegalStateException("Unknown Generic Type")
}
}
Reified type parameter is used to access a type of passed parameter.
Calling the function:
val resultString = read<String>()
try {
val resultInt = read<Int>()
} catch (e: NumberFormatException) {
// make sure to catch NumberFormatException if value can't be cast
}
Generic integer type conversion from and to string
I found a solution with all your ideas, thanks a lot. I've tested the following code, it works the way I want and I made it with a generic sense; I could test other methods to check code efficiency, but it works for me and I hope this idea works for anyone else:
public class HexCnv<T>
{
private MethodInfo _mParse;
private MethodInfo _mToString;
private T _value;
private bool _isPrimitive;
public HexCnv(T v)
{
Type t = typeof(T);
_isPrimitive = t.IsPrimitive;
_value = v;
_mParse = t.GetMethod("Parse", new Type[] { typeof(string), typeof(NumberStyles) });
_mToString = t.GetMethod("ToString", new Type[] { typeof(string) });
}
public HexCnv(string v)
{
Type t = typeof(T);
_isPrimitive = t.IsPrimitive;
_mParse = t.GetMethod("Parse", new Type[] { typeof(string), typeof(NumberStyles) });
_mToString = t.GetMethod("ToString", new Type[] { typeof(string) });
FromString(v);
}
private void FromString(string s)
{
if (_isPrimitive && _mParse != null)
_value = (T)_mParse.Invoke(null, new object[] { s.TrimStart('0', 'x'), NumberStyles.HexNumber });
}
public new string ToString()
{
string sOut = string.Empty;
if (_isPrimitive) sOut = "0x" + _mToString.Invoke(_value, new object[] { "x2" }).ToString();
return sOut;
}
public static implicit operator T(HexCnv<T> v) { return v._value; }
public static implicit operator HexCnv<T>(T v) { return new HexCnv<T>(v); }
public static implicit operator HexCnv<T>(string v) { return new HexCnv<T>(v); }
}
As you can see I changed the static methods, and made it works with simple assigning, see next snippet:
HexCnv<short> mm = "0x1f55";
Console.WriteLine("MM = {0}", (int) mm);
Console.WriteLine("MM-HEX = {0}", mm.ToString());
//This produce the following result
// MM = 8021
// MM-HEX = 0x1f55
HexCnv<short> mm = "0x8f55"; //IDE show no errors on this, but
HexCnv<short> mm = 0x8f55; //It'll give an error on this expression,
//cuz the number is higher than "short"
Conversion from string to generic type
That is not how it works. You can, however, use polymorphism, to achieve a useful result.
Solution with polymorphism
Base generic (and abstract) property
public abstract class Property<T> {
T value;
public abstract void setValue(String input);
}
Property for Strings
public class StringProperty extends Property<String> {
@Override
public void setValue(String input) {
this.value = input;
}
}
Property for integers
public class IntegerProperty extends Property<Integer> {
@Override
public void setValue(String input) {
this.value = Integer.valueOf(input);
}
}
Not sure what your actual goal is, but this approach might work.
Note, that input instanceof T
will fail, because of type erasure. It's not gonna work.
Solution with Class<T>
as argument
To elaborate more on your approach, this would work - but it's UGLY.
Ugly and not very convenient. No idea why you'd want it, tbh.
class Property<T> {
public T value;
private final Class<T> clazz;
public Property(Class<T> clazz) {
super();
this.clazz = clazz;
}
@SuppressWarnings("unchecked")
public void setValue(String input) {
if (clazz.isAssignableFrom(String.class)) {
value = (T) input;
} else if (clazz.isAssignableFrom(Integer.class)) {
value = (T) Integer.valueOf(input);
} else if (clazz.isAssignableFrom(Boolean.class)) {
value = (T) Boolean.valueOf(input);
} else if (clazz.isAssignableFrom(Double.class)) {
value = (T) Double.valueOf(input);
} else {
throw new IllegalArgumentException("Bad type.");
}
}
}
Used like so:
Property<String> ff = new Property<>(String.class);
ff.setValue("sdgf");
Property<Integer> sdg = new Property<>(Integer.class);
sdg.setValue("123");
System.out.println(ff.value);
System.out.println(sdg.value);
Solution with Reflection
Apparently, it's possible to figure out the parameter used to instantiate property.
This little magic formula gives you just that:
(Class<?>) getClass().getTypeParameters()[0].getBounds()[0]
I don't even know how I managed to find it. Well, here we go:
class Property<T> {
T value;
@SuppressWarnings("unchecked")
public void setValue(String input)
{
// BEHOLD, MAGIC!
Class<?> clazz = (Class<?>) getClass().getTypeParameters()[0].getBounds()[0];
if (clazz.isAssignableFrom(String.class)) {
value = (T) input;
} else if (clazz.isAssignableFrom(Integer.class)) {
value = (T) Integer.valueOf(input);
} else if (clazz.isAssignableFrom(Boolean.class)) {
value = (T) Boolean.valueOf(input);
} else if (clazz.isAssignableFrom(Double.class)) {
value = (T) Double.valueOf(input);
} else {
throw new IllegalArgumentException("Bad type.");
}
}
}
And don't look at me, I wouldn't use that. I have some common sense.
Casting string to generic type that is a string
You basically need to go via object
when casting to a generic type:
return (T)(object) v.ToString()
and
return (T)(object) v;
I would use is
rather than catching an InvalidCastException
though.
See Eric Lippert's recent blog post for more details of why this is necessary.
In particular:
Because the compiler knows that the only way this conversion could possibly succeed is if
U
is bool, butU
can be anything! The compiler assumes that most of the timeU
is not going to be constructed withbool
, and therefore this code is almost certainly an error, and the compiler is bringing that fact to your attention.
(Substitute T
for U
and string
for bool
...)
generic type conversion in C#
The only thing I can offer is to improve robustness by using .TryParse()
for the parsing instead of .Parse()
class Program
{
static void Main(string[] args)
{
var i = Parse<int>("100");
var x = Parse<double>("3.1417");
var s = Parse<string>("John");
var d = Parse<Decimal>("1234.56");
var f = Parse<DateTime>("4/1/2044");
var q = Parse<byte>("4A");
Decimal? p = Parse<decimal>("Not Decimal");
}
public static dynamic Parse<T>(string text)
{
var toType = typeof(T);
if (toType == typeof(int))
{
if (int.TryParse(text, out int x))
{
return x;
}
}
else if (toType == typeof(short))
{
if (short.TryParse(text, out short x))
{
return x;
}
}
else if (toType == typeof(double))
{
if (double.TryParse(text, out double x))
{
return x;
}
}
else if (toType == typeof(decimal))
{
if (decimal.TryParse(text, out decimal x))
{
return x;
}
}
else if (toType == typeof(DateTime))
{
if (DateTime.TryParse(text, out DateTime x))
{
return x;
}
}
else if (toType == typeof(byte))
{
if (byte.TryParse(text, System.Globalization.NumberStyles.HexNumber, null, out byte x))
{
return x;
}
}
else if (toType == typeof(string))
{
return text;
}
return null;
}
}
Generic Type Converter - TypeConverter or Convert.ChangeType
In the first example of yours you can get rid of the try catch block by calling CanConvertTo()
and CanConvertFrom()
beforehand.
public static bool TryParse<T>(string source, out T value)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof (T));
if (converter.CanConvertTo(typeof (T)) && converter.CanConvertFrom(typeof (string)))
{
value = (T)converter.ConvertFromString(source);
return true;
}
else
{
value = default (T);
return false;
}
}
In the second example why not make it even more generic and pass in a generic type?
Convert
only works if the type implements the interface IConvertible so you can check for that, on the other hand it stil doesn't ensure that the conversion will be possible.
public static bool TryChangeType<T, TR>(T input, out TR output) where T : IConvertible
{
bool result = false;
try
{
Type type = Nullable.GetUnderlyingType(typeof(TR));
output = (TR)Convert.ChangeType(input, type);
result = true;
}
catch(Exception)
{
output = default(TR);
}
return result;
}
It would be nice to only catch the exceptions you know of:
catch(InvalidCastException)
{
output = default(TR);
//Conversion is not unsupported
}
catch(FormatException)
{
output = default(TR);
//string input value was in incorrect format
}
catch(InvalidCastException)
{
output = default(TR);
//Conversion is not unsupported
}
catch(OverflowException)
{
output = default(TR);
//narrowing conversion between two numeric types results in loss of data
}
This might not answer the question fully, but you were asking for possible improvements so I thought why not.
How to convert a string to generic Type
If I understand your question correctly you want somethiong like this:
public IList GetReferenceDataByType(string referenceType)
{
// this works and returns the appropriate type correctly
var type = this.GetEntity(referenceType);
var method = this.GetType().GetMethod("GetReferenceData");
var generic = method.MakeGenericMethod(type);
return (IList) generic.Invoke(this, new object[] { null });
}
Note that IList<T>
does not implement IList
so that cast may fail.
Related Topics
Internal VS. Private Access Modifiers
How to Find All the Classes Which Implement a Given Interface
How to Align Text in Columns Using Console.Writeline
Best Way to Split String into Lines
How to Extend Identityuser with Custom Property
Get All Registered Routes in ASP.NET Core
Reference Type Still Needs Pass by Ref
C# 3.0 Generic Type Inference - Passing a Delegate as a Function Parameter
How to Get Information About Recently Connected Usb Device
How to Avoid "Too Many Parameters" Problem in API Design
Difference Between Lookup() and Dictionary(Of List())
How Does Entity Framework Work with Recursive Hierarchies? Include() Seems Not to Work with It
How to Know the Size of the String in Bytes
Multi-Tenant with Code First Ef6