Simplify example:
I Have a class with support of direct cast from string
public class MyClass {
public static explicit operator MyClass(string stringValue) => new MyClass();
public static MyClass Parse(string value) => new MyClass();
}
I can cast String to MyClass at compile time like (MyClass)"Some value". But when I cast from string to this class type at runtime, I have Invalid cast from 'System.String' to 'SomeNamespace.MyClass'.
How Can I solve this problem? I need to cast from string to generic class at runtime
I have tried:
var result = Convert.ChangeType("Parsable string", typeof(MyClass));
var converter = TypeDescriptor.GetConverter(typeof(MyClass));
var result = converter.ConvertFromString("Parsable string");
But in both I have an error: Invalid cast from 'System.String' to 'SomeNamespace.MyClass'
So my problem is that String class have no idea how to convert itself to Unknown classes. But all my Unknown classes know how to cast to themselves from String... like (UnknownClass)("Some string value")
About Usecase:
This is a parser for runtime text data models. At runtime I have a IList<string> that represent some Object from external API. I need to convert this IList to my domain Object at Runtime. I can't hardcode concrete class implementation (becouse I only know what object it is at runtime). Here is my implementation, of a generic function that should transform a dictionary of PropertyInfo (of generic object) and Strings (of values from API) to generic object. I think I need some DoDirectCast(Type type, string value) that will direct cast value to type to set parameters of y generic object
public T Transform<T>(Dictionary<PropertyInfo, string> arrOfPropOfT)
{
var returnObject = new T();
foreach (var keyValuePair in arrOfPropOfT)
{
Type propertyType = keyValuePair.value;
string castableValue = keyValuePair.key;
object? value = DoDirectCast(propertyType, castableValue);
propertyInfo.SetValue(returnObject, value)
}
return returnObject;
}
CodePudding user response:
To make TypeDescriptor.GetConverter
work you need to implement TypeConverter
for your class:
[TypeConverter(typeof(MyClassConv))]
public class MyClass
{
public static explicit operator MyClass(string stringValue) => new MyClass();
public static MyClass Parse(string value) => new MyClass();
}
class MyClassConv : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return MyClass.Parse((string)value);
}
}
If you want to go with reflection you can check if type has op_Explicit
defined and invoke it:
var propertyType = typeof(MyClass);
var method = t.GetMethod("op_Explicit", new[] { typeof(string) });
var result = method.Invoke(null, new object[] { "test" });
But reflection is a very heavy tool in general, I would recommend you at least considering building and compiling expression trees for this usecase. Or maybe even better looking into source generators.