У меня есть класс с поддержкой прямого приведения из строки
public class MyClass {
public static explicit operator MyClass(string stringValue) => new MyClass();
public static MyClass Parse(string value) => new MyClass();
}
Я могу привести String к MyClass во время компиляции, например (MyClass) «Некоторое значение». Но когда я привожу из строки к этому типу класса во время выполнения, у меня происходит недопустимое приведение из «System.String» в «SomeNamespace.MyClass».
Как я могу решить эту проблему? Мне нужно преобразовать строку в общий класс во время выполнения
var result = Convert.ChangeType("Parsable string", typeof(MyClass));
var converter = TypeDescriptor.GetConverter(typeof(MyClass));
var result = converter.ConvertFromString("Parsable string");
Но в обоих случаях у меня ошибка: Неверное преобразование из «System.String» в «SomeNamespace.MyClass».
Итак, моя проблема в том, что класс String понятия не имеет, как преобразовать себя в неизвестные классы. Но все мои Неизвестные классы умеют приводить к себе из String... например (UnknownClass)("Некоторое строковое значение")
Это парсер для моделей текстовых данных во время выполнения. Во время выполнения у меня есть IList<string>, который представляет некоторый объект из внешнего API. Мне нужно преобразовать этот IList в объект моего домена во время выполнения. Я не могу жестко закодировать конкретную реализацию класса (потому что я знаю, что это за объект, только во время выполнения). Вот моя реализация универсальной функции, которая должна преобразовывать словарь PropertyInfo (общий объект) и строки (значения из API) в универсальный объект. Я думаю, мне нужен некоторый DoDirectCast (тип типа, строковое значение), который будет направлять значение приведения к типу, чтобы установить параметры универсального объекта y
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;
}
Чтобы заставить TypeDescriptor.GetConverter
работать, вам нужно реализовать TypeConverter
для своего класса:
[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);
}
}
Если вы хотите использовать отражение, вы можете проверить, определен ли тип op_Explicit
, и вызвать его:
var propertyType = typeof(MyClass);
var method = t.GetMethod("op_Explicit", new[] { typeof(string) });
var result = method.Invoke(null, new object[] { "test" });
Но рефлексия в целом — очень тяжелый инструмент, я бы рекомендовал вам хотя бы подумать о построении и компиляции деревьев выражений для этого варианта использования. Или, может быть, даже лучше изучить генераторы исходников.
Спасибо! Именно эту работу я и хочу! Я буду читать больше о деревьях выражений и генераторах исходного кода. Reflection — очень тяжелый инструмент в целом для производительности или для поддержки и разработки?
@AlexTerkov для обоих. Но предлагаемые инструменты потенциально могут решить только проблему с производительностью.
Есть обходной путь с JSON. Я могу преобразовать IList<string> и список PropertiInfo в одну строку в формате json, а затем использовать Newtosoft Deserialization для получения объекта. Но это какое-то странное решение. Будет намного лучше сделать это без преобразования в строку json и Newtonsoft.