如何在运行时将字符串对象转换为通用对象?

How to convert string object to generic object at runtime?

提问人:Alex Terkov 提问时间:11/27/2022 最后编辑:Alex Terkov 更新时间:11/27/2022 访问量:323

问:

简化示例:

我有一个支持从字符串直接转换的类

public class MyClass {
    public static explicit operator MyClass(string stringValue) => new MyClass();
    public static MyClass Parse(string value) => new MyClass();
}

我可以在编译时将字符串转换为 MyClass,例如 (MyClass)“Some value”。但是当我在运行时从字符串转换为此类类型时,我从“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 类不知道如何将自身转换为 Unknown 类。但是我所有的 Unknown 类都知道如何从 String 投射到自己身上......like (UnknownClass)(“一些字符串值”)

关于用例:

这是运行时文本数据模型的分析器。在运行时,我有一个IList<string>它表示来自外部API的一些对象。我需要在运行时将此 IList 转换为我的域对象。我无法对具体的类实现进行硬编码(因为我只知道它在运行时是什么对象)。这是我的实现,一个泛型函数,它应该将 PropertyInfo(泛型对象)和 Strings(来自 API 的值)的字典转换为泛型对象。我想我需要一些DoDirectCast(Type type, string value),它将把值定向到类型以设置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;
}
C# .NET 反射 转换 运行时

评论

0赞 Alex Terkov 11/27/2022
JSON有解决方法。我可以将 IList<string> 和 PropertiInfo 列表转换为一个 json 格式的字符串,然后使用 Newtosoft 反序列化来获取对象。但这是一个有点奇怪的解决方案。在不转换为 json 字符串和 Newtonsoft 的情况下这样做会好得多

答:

0赞 Guru Stron 11/27/2022 #1

要完成工作,您需要为类实现:TypeDescriptor.GetConverterTypeConverter

[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" });

但总的来说,反射是一个非常繁重的工具,我建议你至少考虑为这个用例构建和编译表达式树。或者甚至更好地研究源生成器

评论

0赞 Alex Terkov 11/27/2022
谢谢!那件作品正是我想要的!我将阅读有关表达式树和源生成器的更多信息。反射通常是一个非常沉重的工具,用于性能或支持和发展?
0赞 Guru Stron 11/27/2022
两者都@AlexTerkov。但建议的工具可能只能解决性能问题。