2

我有以下代码:

var ad = product.AttributesDictionary;
var ddl = product.DetailedDescriptionList;
var rdl = product.RelatedProductList;

我读过 C#/JIT 编译器可以做很多优化。由于赋值后不使用变量。我担心 C#/JIT 编译器可能会省略这些行以进行优化。

请不要告诉我删除此行。

更新:我认为没有人能够理解我的意思。我的问题是,如果您将属性分配给变量然后不使用此变量,C#/JIT 编译器是否会忽略此代码?

4

5 回答 5

4

(这不是特定于 C# 编译器的,它只是一般的观察)

将属性分配给变量实际上有两个部分:

  1. 执行属性的get方法
  2. 将方法的返回值赋给变量。

由于第一部分可以像任何方法一样复杂,并且有很多副作用,所以没有编译器会优化它。

如果在赋值后没有使用变量,则可以优化第二部分,如果编译器正在积极优化。


但是,还有另一种优化器的行为方式不太可预测 - 下一个看到该代码的开发人员。

这些行看起来好像什么也没做,所以如果下一个看到它们的人是一个讨厌多余代码的书呆子(就像大多数开发人员一样),这些行可以在不看一眼的情况下被删除。

尝试找到一种更好、更明确的方式来完成你试图用这些行完成的任何事情;

于 2013-09-17T11:40:55.613 回答
1

好吧,让我们看看规范对此有何评论:

第 3.10 节:执行顺序

继续执行 C# 程序,以便在关键执行点保留每个执行线程的副作用。副作用定义为对易失性字段的读取或写入、对非易失性变量的写入、对外部资源的写入以及抛出异常。

[..]

此外,如果执行环境可以推断出该表达式的值未被使用并且没有产生所需的副作用(包括由调用方法或访问易失性字段引起的任何副作用),则执行环境不需要评估该表达式的一部分。

由于您的代码显然有可能引发异常,因此如果访问被优化掉,这将是一个编译器错误。

所以这段代码在技术上是安全的。从访问器中抛出异常不仅符合法律条文,而且符合精神:访问器是方法,方法当然可以根据具体情况进行抛出。

然而,在这段代码的面向人类的一面,事情看起来并不好。如果您有合理的期望希望检查某些内容,则您的代码应启用此功能:

obj.TrySomething()

它不应该要求您这样做:

try { obj.DoSomething(); }
catch (SomeException e) { ... }
于 2013-09-17T11:45:33.343 回答
1

您可以通过将此代码编译成程序集(DLL 或 EXE)然后使用ILDASM将其转换为纯文本 IL 来找到答案。

由于 JIT 将 IL 转换为 x86/x64 机器代码,这仍然无法准确告诉您运行时发生了什么。但是 Visual Studio 调试器会向您展示为此的反汇编,让您可以进一步挖掘。

于 2013-09-17T11:46:01.307 回答
1

我已经尝试过了,使用以下代码:

public class Example
{
    public string SomeProperty { get; set; }

    public static void DoSomething(Example instance)
    {
        var value = instance.SomeProperty;
    }
}

该方法DoSomething编译为以下 IL(由 ILSpy 提供):

.method public hidebysig static 
    void DoSomething (
        class Example 'instance'
    ) cil managed 
{
    // Method begins at RVA 0x2061
    // Code size 8 (0x8)
    .maxstack 8
    IL_0000: ldarg.0
    IL_0001: callvirt instance string Example::get_SomeProperty()
    IL_0006: pop
    IL_0007: ret
} // end of method Example::DoSomething

您将看到get_SomeProperty()调用了属性访问器,即使在可以编写的最基本的属性访问器的情况下,并且在同一程序集中定义类型时也是如此。

于 2013-09-17T11:47:49.053 回答
1

如果您尝试使用虚拟调用强制初始化享元缓存,那么您可以尝试ToString(),就像product.AttributesDictionary.ToString();我相信编译器不会省略该行一样。您可能需要product.AttributesDictionary根据缓存的行为检查是否为空。

于 2013-09-17T11:41:49.163 回答