属性/方法内联及其对反射的影响

9

我在stackoverflow的一个问题中回答时,Valentin Kuzub发表了评论,他认为通过JIT编译器内联属性会导致反射无法正常工作。

具体情况如下:

class Foo
{
    public string Bar { get; set; }

    public void Fuzz<T>(Expression<Func<T>> lambda)
    {
    }
}

Fuzz(x => x.Bar);

Fuzz函数接受一个lambda表达式,并使用反射查找属性。在MVC中,这是HtmlHelper扩展中的常见做法。

我认为即使Bar属性被内联,反射也不会停止工作,因为它是调用Bar的内容将被内联,typeof(Foo).GetProperty("Bar")仍然会返回一个有效的PropertyInfo

请确认一下,或者我的方法内联理解有误吗?


顺便说一下,我发现了这篇有趣的文章,展示了在INotifyPropertyChange实现中不使用lambda表达式的其他原因。http://blog.quantumbitdesigns.com/2010/01/26/mvvm-lambda-vs-inotifypropertychanged-vs-dependencyobject/ - Valentin Kuzub
4个回答

3
JIT编译器在运行时操作,无法重写存储在程序集中的元数据信息。而反射读取程序集以访问此元数据。因此,JIT编译器对反射没有任何影响。
编辑: 实际上,在编译过程中,C#编译器本身会“内联”一些信息。例如,常量、枚举和默认参数都被“内联”,因此您无法在反射期间访问它们。但这与您的特定情况无关。

默认属性是什么意思? - leppie
您可以将“枚举”添加到您的列表中。 - Jakub Konecki

1

是的,当我更深入地思考时,我想唯一可能导致内联属性失败的情况是如果您正在使用反射方法,例如

public Count
{
get {return m_Count;}
 set { m_Count=value;
      GetCurrentPropertyNameUsingReflectionAndNotifyItChanged();}
}

如果你像你所建议的那样使用,元数据确实存在于程序集中,并且属性名称将成功从那里获取。

不过,这让我们俩都开始思考了。


如何确切地调用方法?该方法不会从属性中调用,而是从使用该属性的方法中调用,并且结果名称不会是Count,而是另一个不同的名称(很可能是方法名称,而不是属性名称)。 - Valentin Kuzub
你的方法 GetCurrentPropertyNameUsingReflectionAndNotifyItChanged 是否分析调用堆栈? - Jakub Konecki
是的。正如您所看到的,它没有传递任何参数。这是一种基于通用反射的方法,如果不进行内联处理,则非常好。在ViewModel基类中实现一个方法,在所有属性中调用它并享受其中。 - Valentin Kuzub
然后,您必须使用“MethodImplAttribute”标记您的属性以停止内联。 - Jakub Konecki

0

我个人同意@Sergey的观点:

考虑到内联发生在JIT编译器端,而元数据是在之前生成的,所以它不应该对反射产生任何影响。顺便说一句,好问题,赞+1。


0

表达式树无法进行内联,因为它们是表达式的表示(抽象语法树),而不是表达式本身。

委托即使可以内联,仍将在其属性中携带有关所调用方法和目标的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接