为什么我需要在运行时编译/生成方法/代码?

时间:2014-12-31 12:49:20

标签: c# ruby reflection lambda monkeypatching

我对理论方面很感兴趣。在典型的日常编程场景中,C#在运行时使用Codedom / Reflection或Lambda表达式/表达式树来生成代码需要什么?不是在特殊情况下

或者像Ruby这样的其他语言,为什么要在运行时使用monkeypatching来添加/修改类?

这有什么优势?

3 个答案:

答案 0 :(得分:2)

在Ruby中,生成方法的方法无处不在

例如,有生成setter和getter方法的方法:

class Module
  def attr_reader(*attributes)
    attributes.each do |attribute|
      define_method(attribute) do instance_variable_get(:"@#{attribute}") end
    end
  end

  def attr_writer(*attributes)
    attributes.each do |attribute|
      define_method(:"#{attribute}=") do |value|
        instance_variable_set(:"@#{attribute}", value)
      end
    end
  end

  def attr_accessor(*attributes)
    attr_reader(*attributes)
    attr_writer(*attributes)
  end
end

当我调用这样的方法之一时:

attr_reader :bla

这将生成一个名为bla的方法,该方法返回名为@bla的实例变量的值。

attr_writer :bla

将生成一个名为bla=的方法(在末尾用等号命名方法是Ruby中setter的通常命名约定),它将其参数赋给名为@bla的实例变量。< / p>

class Foo
  attr_reader   :foo,    :bar
  attr_writer   :baz,    :quux
  attr_accessor :gargle, :blarf
end

这将生成方法foobarbaz=quux=garglegargle=blarf,{ {1}}。

另一个例子是Ruby的blarf= ORM库,它基于在运行时反映数据库模式,为模型生成getter和setter方法以及finder方法。

ActiveRecord也有动态查找程序方法,可让您执行ActiveRecord之类的操作。当然,人们可能想要搜索的数据库列有无限多种组合,因此提前生成所有方法是不切实际的。相反,Person.find_by_name_and_age('John', 42)会安装ActiveRecord挂钩来拦截对以method_missing开头的不存在方法的调用。但是,一旦它截获了一个方法调用,它就会生成一个该名称的方法,假设该方法可能在时间内被更频繁地调用,因此动态拦截可以是侧面步骤。

一般来说, Code Synthesis 代码生成有用的任何地方都很有用,但具有显着优势

  • 它不会使您的源树混乱,因为所有生成的&#34;代码&#34;是短暂的
  • 您使用的是语言&#39;自己设置生成代码,所以它(在某种意义上)总是正确的,而使用(简单的文本)代码生成,你将不得不小心生成语法上有效的代码

答案 1 :(得分:1)

我遇到过几个案例。一个案例是出于性能原因。例如当您存储创建对象的已编译委托时。比如一些IoC框架。这些编译后的代表往往创建起来很慢,但如果多次调用相同的委托,执行速度非常快可以提供良好的性能提升。

我遇到的另一个案例是使用谓词构建动态过滤器,然后在数据库中序列化这些过滤器,以便用户不需要再次定义它们。

答案 2 :(得分:1)

有时你必须牺牲完整的清洁代码来获得大量的生产力和进化。

例如,如果您开发了1000个类并为每个类创建二进制序列化程序。通过反射和代码生成来实现它非常容易。与许多静态代码相比,维护独特的动态代码要困难得多。在对动态代码进行完全认证后,风险实际上已降至最低。

幸运的是,通用涵盖了这个问题的很大一部分。

在处理一个小项目时,在运行时生成msil是没用的。

另一个考虑因素是水平发展(公用事业/帮助者)不依赖于直接业务发展。