【问题标题】: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() 有没有其他方法可以使用这个功能?

【问题讨论】:

    标签: c# generics methods


    【解决方案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 更改为非泛型形式,因为它是否真的应该是泛型的尚不清楚。

        【讨论】:

        • 我只是为了解释而简化了程序。这实际上是最优雅的解决方案,信不信由你。 :) 谢谢!
        猜你喜欢
        • 1970-01-01
        • 2020-02-23
        • 2020-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多