Как преобразовать строковый объект в общий объект во время выполнения?

Упростить пример:

У меня есть класс с поддержкой прямого приведения из строки

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;
}

Есть обходной путь с JSON. Я могу преобразовать IList<string> и список PropertiInfo в одну строку в формате json, а затем использовать Newtosoft Deserialization для получения объекта. Но это какое-то странное решение. Будет намного лучше сделать это без преобразования в строку json и Newtonsoft.

Alex Terkov 27.11.2022 10:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
178
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы заставить 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 — очень тяжелый инструмент в целом для производительности или для поддержки и разработки?

Alex Terkov 27.11.2022 12:27

@AlexTerkov для обоих. Но предлагаемые инструменты потенциально могут решить только проблему с производительностью.

Guru Stron 27.11.2022 12:28

Другие вопросы по теме