使用运行时类型执行的通用方法[重复]

Posted

技术标签:

【中文标题】使用运行时类型执行的通用方法[重复]【英文标题】:Generic Method Executed with a runtime type [duplicate] 【发布时间】:2009-10-22 12:46:09 【问题描述】:

我有以下代码:

 public class ClassExample


    void DoSomthing<T>(string name, T value)
    
        SendToDatabase(name, value);
    

    public class ParameterType
    
        public readonly string Name;
        public readonly Type DisplayType;
        public readonly string Value;

        public ParameterType(string name, Type type, string value)
        
            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");
            if (type == null)
                throw new ArgumentNullException("type");

            this.Name = name;
            this.DisplayType = type;
            this.Value = value;
        
    

    public void GetTypes()
    
        List<ParameterType> l = report.GetParameterTypes();

        foreach (ParameterType p in l)
        
            DoSomthing<p.DisplayType>(p.Name, (p.DisplayType)p.Value);
        

    

现在,我知道我无法执行 DoSomething() 有没有其他方法可以使用这个功能?

【问题讨论】:

【参考方案1】:

你可以,但它涉及到反思,但你可以做到。

typeof(ClassExample)
    .GetMethod("DoSomething")
    .MakeGenericMethod(p.DisplayType)
    .Invoke(this, new object[]  p.Name, p.Value );

这将查看包含类的顶部,获取方法信息,创建具有适当类型的泛型方法,然后您可以对其调用 Invoke。

【讨论】:

只是一个问题,p.Value 是一个字符串,因此调用将失败,除非 p.DisplayType 恰好是 typeof(string)。 很遗憾这是唯一的解决方案,嗯 好吧,我认为您可以在 4.0 中使用动态,它会推断出正确的通用参数类型,但我还没有机会验证它。并不是说它在幕后做的事情与上面的代码不同,但也许确实如此。【参考方案2】:
this.GetType().GetMethod("DoSomething").MakeGenericMethod(p.Value.GetType()).Invoke(this, new object[]p.Name, p.Value);

应该可以。

【讨论】:

关于简洁:可以并不意味着应该【参考方案3】:

泛型类型不能在运行时按照您希望的方式指定。

最简单的选项是添加DoSomething 的非泛型重载,或者直接调用DoSomething&lt;object&gt; 并忽略p.DisplayType。除非SendToDatabase 依赖于value编译时 类型(它可能不应该),否则给它一个object 应该没有错。

如果你不能这样做,你将不得不使用反射调用DoSomething,你会受到很大的性能影响。

【讨论】:

【参考方案4】:

首先我们需要将p.Value 转换为正确的类型,因为即使我们在编译时知道类型,我们也无法将字符串直接传递给方法...

DoSomething<Int32>( "10" ); // Build error

对于简单的数值类型和DateTime,我们可以使用

object convertedValue = Convert.ChangeType(p.Value, p.DisplayType);

现在我们可以使用反射来调用所需的泛型方法...

typeof(ClassExample)
    .GetMethod("DoSomething")
    .MakeGenericMethod(p.DisplayType)
    .Invoke(this, new object[]  p.Name, convertedValue );

【讨论】:

【参考方案5】:

严格来说,您可以为此使用MethodInfo.MakeGenericMethod。

但我建议改为将 DoSomething 更改为非泛型形式,因为它是否真的应该是泛型的尚不清楚。

【讨论】:

我只是为了解释而简化了程序。这实际上是最优雅的解决方案,信不信由你。 :) 谢谢!

以上是关于使用运行时类型执行的通用方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 Lambda 表达式调用通用方法(以及仅在运行时知道的类型)

通用传递类型列表以用于通用方法[重复]

具有不满意类型约束的通用方法是隐藏扩展方法[重复]

Java中的通用方法-如何将参数类类型作为返回类型返回[重复]

C#从反射类型实例化通用列表[重复]

无法在通用方法中将整数转换为枚举 [重复]