2009-10-22 38 views
25

我有以下代码:通用方法中执行一个运行时类型

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的() 有没有使用此功能的任何其他方式?

回答

29

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

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

这将着眼于包含类的顶部,获得方法的信息,创建具有相应类型的通用方法,那么你可以调用来调用它。

+0

只有一个catch,p.Value是一个字符串,所以调用将失败,除非p.DisplayType碰巧是typeof(string)。 – stevemegson 2009-10-22 13:39:57

+1

惭愧这是唯一的解决方案,meh – 2009-11-16 21:54:58

+1

嗯,我想你可以在4.0中使用动态,它会推断正确的泛型参数类型,但我还没有机会验证它。并不是说它在封面上做的和上面的代码不同,但也许是这样。 – 2009-11-16 22:11:11

5
this.GetType().GetMethod("DoSomething").MakeGenericMethod(p.Value.GetType()).Invoke(this, new object[]{p.Name, p.Value}); 

应该工作。

3

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

最简单的选择是添加DoSomething的非通用超载,或者只需调用DoSomething<object>并忽略p.DisplayType。除非SendToDatabase取决于编译时间类型的value(它可能不应该),那么给它一个object应该没有问题。

如果你不能做到这些,你将不得不使用反射来调用DoSomething,并且你将获得巨大的性能。

1

严格地说你可以使用MethodInfo.MakeGenericMethod这个。

但我建议将DoSomething改为非泛型形式,因为它不是真的应该是通用的。

+0

我只是简化了解释程序。这实际上是最优雅的解决方案,信不信由你。 :) 谢谢! – Sarit 2009-10-22 12:57:36

3

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

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

对于简单的数字类型和日期时间,我们可以使用

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

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

typeof(ClassExample) 
    .GetMethod("DoSomething") 
    .MakeGenericMethod(p.DisplayType) 
    .Invoke(this, new object[] { p.Name, convertedValue }); 
相关问题