.net ConditionalAttribute应该去掉整行,还是仅仅是方法调用?
根据课程的文档: 将条件属性应用于 方法向编译器指示 对方法的调用不应为空 编译成微软中间版本 语言(MSIL),除非条件 关联的编译符号 定义了带有条件的属性 对我来说,这意味着.net ConditionalAttribute应该去掉整行,还是仅仅是方法调用?,.net,debugging,conditional,release,.net,Debugging,Conditional,Release,根据课程的文档: 将条件属性应用于 方法向编译器指示 对方法的调用不应为空 编译成微软中间版本 语言(MSIL),除非条件 关联的编译符号 定义了带有条件的属性 对我来说,这意味着Conditional属性只改变单个方法调用级别的行为。但是请考虑下面的代码片段: class InstanceType { public InstanceType DoSideEffects() { Console.WriteLine("Side effects!");
Conditional
属性只改变单个方法调用级别的行为。但是请考虑下面的代码片段:
class InstanceType
{
public InstanceType DoSideEffects()
{
Console.WriteLine("Side effects!");
return this;
}
public InstanceType DoMoreSideEffects()
{
Console.WriteLine("More side effects!");
return this;
}
[Conditional("DEBUG")]
public void ConditionalMethod()
{
Console.WriteLine("Conditional method run.");
}
}
class Program
{
static void Main()
{
var x = new InstanceType();
// The compiler appears to strip out this entire line
// in a Release build.
x.DoSideEffects().DoMoreSideEffects().ConditionalMethod();
var y = new InstanceType();
// When each method call appears on its own line,
// the first two methods are included as expected.
y.DoSideEffects();
y.DoMoreSideEffects();
y.ConditionalMethod();
}
}
比较调试版本和发布版本的输出:
DEBUG RELEASE
Side effects! Side effects!
More side effects! More side effects!
Conditional method run.
Side effects!
More side effects!
Conditional method run.
调试版本
副作用!副作用!
更多的副作用!更多的副作用!
条件方法运行。
副作用!
更多的副作用!
条件方法运行。
这个行为是在什么地方指定的吗?我原以为两个构建应该有相同的输出,除了读“条件方法运行”的行。有趣的特性:-)我从来没有注意到这一点
我已经看了一眼IL。这并不能解释行为(编译过程),但我相信它记录了结果
整个C#代码行在IL中明显遗漏了:
- 在调试编译中,一个新对象 创建(x变量),存储 在位置0处加载。之后 应用这三种方法 依次为:dosDeEffects(), DeMoreSideEffects(),以及 条件方法()
- 在版本编译中,仍然会创建变量,但由于不需要它,因此会立即弹出该变量。相反,y变量存储在位置0并加载李>
// DEBUG compilation
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 58 (0x3a)
.maxstack 1
.locals init (class ConsoleApplication3.InstanceType V_0,
class ConsoleApplication3.InstanceType V_1)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication3.InstanceType::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects()
IL_000d: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects()
IL_0012: callvirt instance void ConsoleApplication3.InstanceType::ConditionalMethod()
IL_0017: nop
IL_0018: newobj instance void ConsoleApplication3.InstanceType::.ctor()
IL_001d: stloc.1
IL_001e: ldloc.1
IL_001f: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects()
IL_0024: pop
IL_0025: ldloc.1
IL_0026: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects()
IL_002b: pop
IL_002c: ldloc.1
IL_002d: callvirt instance void ConsoleApplication3.InstanceType::ConditionalMethod()
IL_0032: nop
IL_0033: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_0038: pop
IL_0039: ret
} // end of method Program::Main
// RELEASE compilation
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 33 (0x21)
.maxstack 1
.locals init ([0] class ConsoleApplication3.InstanceType y)
IL_0000: newobj instance void ConsoleApplication3.InstanceType::.ctor()
IL_0005: pop
IL_0006: newobj instance void ConsoleApplication3.InstanceType::.ctor()
IL_000b: stloc.0
IL_000c: ldloc.0
IL_000d: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects()
IL_0012: pop
IL_0013: ldloc.0
IL_0014: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects()
IL_0019: pop
IL_001a: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_001f: pop
IL_0020: ret
} // end of method Program::Main
很抱歉,我拖了这么一篇老文章,但我遇到了同样的事情,这是我能找到的关于这个问题的唯一讨论 我对正在发生的事有预感。
[Conditional]
正在剥离对ConditionalMethod()
的调用以及作为传递给它的参数的任何表达式(根据文档和上面链接的其他线程)
我猜想隐式这个参数的处理方式是完全相同的。在x行中。DoSideEffects().DoMoreSideEffects().ConditionalMethod()
作为this
传递的表达式是x.DoSideEffects().DoMoreSideEffects()
,它被尽职地剥离,消除了副作用
如果我们重写为伪代码,在其中显式地传递这个
作为每个方法的第一个参数,它会变得更加清晰:
ConditionalMethod(DoMoreSideEffects(x))代码>我对[条件]
的理解与你的理解相同,我认为你看到了优化的效果。在发布模式下,IL看起来是什么样子?有趣的是,如果不定义调试,在第一种情况下,即使是Visual Studio(或者它是ReSharper?)也会将整行显示为灰色/未使用。而在第二个问题中,它只将对ConditionalMethod()的调用着色为灰色/unused。。。但是,另一个问题询问了由于评估传递给标有条件属性的方法的参数而产生的副作用。这是关于方法调用的序列,提供调用所述方法的实例。因此,我觉得这两个方面是非常不同的。如果其他人不同意并投票关闭,我想这也没关系。没错,尽管这个问题的答案回答了你的问题(特别是关于条件属性所取代的\If
/\endif
)。