没有泛型参数的反射转换为类型

Posted

技术标签:

【中文标题】没有泛型参数的反射转换为类型【英文标题】:Cast to Type with reflection without generic argument 【发布时间】:2021-07-05 12:36:43 【问题描述】:

我有一个涉及转换为不同类型的问题

我有一个包装器类,它包含一个内部包装器,其中包含T 这是结构:

public class Wrapper

    public readonly Guid Foo;

    public Wrapper(Guid foo)
    
        Foo = foo;
    


public class Wrapper<T> : Wrapper

    public readonly InnerWrapper<T> InnerWrapper;

    public Wrapper(Guid foo, InnerWrapper<T> innerWrapper) 
        : base(foo)
    
        InnerWrapper = innerWrapper;
    


public class InnerWrapper<T> 

    public readonly Guid Bar;
    public readonly T Content;
    public InnerWrapper(T content, Guid bar)
    
        Content = content;
        Bar = bar;
    

在代码的另一部分我有一个List&lt;Wrapper&gt;。请注意,这是一个包装器列表,而不是 wrapper&lt;T&gt; 列表,这意味着 T 可以是任何类。 当这个翻译预计会有类似的东西


    wrapper<Class1>,
    wrapper<Class2>

等等。

在代码中的某个位置有一个“帮助类”,其中包含object 类型的对象和Type

public class Helper

    public readonly object Obj;
    public readonly Type Type;

    public Helper(object obj, Type type)
    
        Obj = obj;
        Type = type;
    

这就是我的问题开始的地方,我创建了一个辅助方法来从 List&lt;Helper&gt; 转换为 List&lt;Wrapper&gt; 并且它做到了,但内部对象是 object 类型而不是实际类型。

而且我不知道如何在不使用泛型的情况下将 object 转换为实际类型,并且由于 T 可以是多个类型,我无法使用它们。

这是辅助类

public static class HelperExtensions

    public static T CastTo<T>(this object o) => (T)o;

    public static List<Wrapper> ToWrapper(this IEnumerable<Helper> helperList)
    
        List<Wrapper> wrapperResponseList = new List<Wrapper>();
        foreach (var help in helperList)
        
            // doesn't work either var typedValue = Convert.ChangeType(help.Obj, help.Type);

            var methodInfo = typeof(HelperExtensions).GetMethod(nameof(CastTo), BindingFlags.Static | BindingFlags.Public);
            var genericArguments = new[]  help.Type ;
            var genericMethodInfo = methodInfo?.MakeGenericMethod(genericArguments);
            var typedValue = genericMethodInfo?.Invoke(null, new[]  help.Obj );

            var wrapper = typedValue.BuildWrapper(Guid.NewGuid(), Guid.NewGuid());

            wrapperResponseList.Add(wrapper);
        

        return wrapperResponseList;
    


    //This one called individually does the work properly
    public static Wrapper<T> BuildWrapper<T>(this T obj, Guid foo, Guid bar)
    
        InnerWrapper<T> inner = new InnerWrapper<T>(obj, bar);
        return new Wrapper<T>(foo, inner);
    


为了在这里显示代码,我还创建了一个测试类

public class Placeholder

    public Guid Value  get; 

    public Placeholder(Guid value)
    
        Value = value;
    

所以当我打电话时

Placeholder placeholder = new Placeholder(Guid.NewGuid());
Helper helper1 = new Helper(placeholder, placeholder.GetType());
var result = new List<Helper>  helper1 .ToWrapper();

它生成一个List&lt;Wrapper&gt;,但它生成的不是wrapper&lt;T&gt;,而是Wrapper&lt;Object&gt;

知道如何正确投射吗?

我还创建了一个小提琴https://dotnetfiddle.net/pz3JDz,其中包含所有需要测试的代码。

提前感谢您的帮助。

【问题讨论】:

你为什么不直接调用 BuildWrapper&lt;T&gt; 作为泛型?类似typeof(HelperExtensions).GetMethod("BuildWrapper").MakeGenericMethod(new[] help.Type).Invoke(this,help.Obj) @Franck 我没有想到那个选项;有效。回答问题,以便我给你打绿色勾:D,谢谢。 【参考方案1】:

局部变量typedValuevar声明,因为genericMethodInfo?.Invoke(...)返回object类型的回复,所以该局部变量typedValue的类型将是object。之后在这里调用泛型方法Wrapper&lt;T&gt; BuildWrapper&lt;T&gt;(this T obj, ...),因为typedValue 的类型是objectT 的类型也是object,因此它会返回Wrapper&lt;object&gt;

解决它而不是这个:

var wrapper = typedValue.BuildWrapper(Guid.NewGuid(), Guid.NewGuid());

这样做:

var buildWrapperMethodInfo = typeof(HelperExtensions).GetMethod(nameof(BuildWrapper), BindingFlags.Static | BindingFlags.Public);
var buildWrapperGenericMethodInfo = buildWrapperMethodInfo?.MakeGenericMethod(genericArguments);
var wrapper = buildWrapperGenericMethodInfo?.Invoke(null, new[]  typedValue, Guid.NewGuid(), Guid.NewGuid() );

然后在此处添加类型转换:

wrapperResponseList.Add((Wrapper)wrapper);

【讨论】:

【参考方案2】:

可以简化直接从BuildWrapper&lt;T&gt; 检索对象的调用。 您可以执行以下操作。您显然可以重新格式化以进行错误检查,但您明白了。

var wrapperGeneric = typeof(HelperExtensions).GetMethod("BuildWrapper").MakeGenericMethod(new[]  help.Type).Invoke(this,help.Obj)

【讨论】:

以上是关于没有泛型参数的反射转换为类型的主要内容,如果未能解决你的问题,请参考以下文章

泛型技巧系列:如何提供类型参数之间的转换

java泛型

无法将类型“Int”的值转换为泛型中的预期参数类型“Int”

泛型中的类型擦除

Java泛型

在泛型方法中返回特定类型,具体取决于运行时没有反射或动态的枚举值