[英]In VB.NET, C#, etc., does the one-dot rule automatically get optimized into the code?
在VB.NET,C#等中,这样的东西不会得到优化,是吗?
'Bad
a.B.C.DoSomething1()
a.B.C.DoSomething2()
a.B.C.X = 5
DoSomething3(a.B.C.D)
'Good
Dim cachedReference As ClassOfC = a.B.C
cachedReference.DoSomething1()
cachedReference.DoSomething2()
cachedReference.X = 5
DoSomething3(cachedReference.D)
至少在ECMA类型的语言中,这是一个好习惯,要尽量减少它进入a
,然后转到其B
字段/属性,最后到其C
字段/属性。 我认为这通常是任何典型的面向对象或过程语言中的经验法则,除非至少有一个明确的期望,那就是它将像编译器/ jit / etc那样得到优化。 无论如何。 在典型的.NET(特别是VB.NET和C#)中如何处理?
例如,这似乎没有提到单点规则,至少与这两种语言之一有关: https : //msdn.microsoft.com/zh-cn/library/ms973839.aspx 。 另一方面,如果对属性进行一般设置,我会感到非常惊讶,因为它们是有效的方法。 如果这样做,并且仅当它们是字段,甚至可能是完全无关紧要的属性时,这样做似乎更有意义。
好吧,出于好奇,我继续尝试了一下。
给定以下类别:
public class Foo
{
public Bar Bar { get; set;}
}
public class Bar
{
public Baz Baz { get; set;}
}
public class Baz
{
public string One { get; set; } = string.Empty;
public string Two { get; set; } = string.Empty;
public bool BothPopulated() => !(string.IsNullOrWhiteSpace(One) || string.IsNullOrWhiteSpace(Two));
}
public class FooFactory
{
public static Foo Create() => new Foo { Bar = new Bar { Baz = new Baz { One = "Hello", Two = "World" } } };
}
和以下方法:
void Main()
{
var foo = FooFactory.Create();
var cached = foo.Bar.Baz;
Console.WriteLine(cached.One);
Console.WriteLine(cached.Two);
Console.WriteLine(cached.BothPopulated());
var fooTwo = FooFactory.Create();
Console.WriteLine(fooTwo.Bar.Baz.One);
Console.WriteLine(fooTwo.Bar.Baz.Two);
Console.WriteLine(fooTwo.Bar.Baz.BothPopulated());
}
LinqPad将释放模式下的main发出的IL报告为
IL_0000: call UserQuery+FooFactory.Create
IL_0005: callvirt UserQuery+Foo.get_Bar
IL_000A: callvirt UserQuery+Bar.get_Baz
IL_000F: dup
IL_0010: callvirt UserQuery+Baz.get_One
IL_0015: call System.Console.WriteLine
IL_001A: dup
IL_001B: callvirt UserQuery+Baz.get_Two
IL_0020: call System.Console.WriteLine
IL_0025: callvirt UserQuery+Baz.BothPopulated
IL_002A: call System.Console.WriteLine // <- End of cached portion
IL_002F: call UserQuery+FooFactory.Create
IL_0034: dup
IL_0035: callvirt UserQuery+Foo.get_Bar
IL_003A: callvirt UserQuery+Bar.get_Baz
IL_003F: callvirt UserQuery+Baz.get_One
IL_0044: call System.Console.WriteLine
IL_0049: dup
IL_004A: callvirt UserQuery+Foo.get_Bar
IL_004F: callvirt UserQuery+Bar.get_Baz
IL_0054: callvirt UserQuery+Baz.get_Two
IL_0059: call System.Console.WriteLine
IL_005E: callvirt UserQuery+Foo.get_Bar
IL_0063: callvirt UserQuery+Bar.get_Baz
IL_0068: callvirt UserQuery+Baz.BothPopulated
IL_006D: call System.Console.WriteLine
IL_0072: ret
因此,看起来您确实通过不每次都钻取属性来保存了一些callvirt。 我无法回答这是否会对运行时的JIT产生任何可衡量的影响,但是它确实留下了较小的IL占用空间。
我怀疑它对运行时性能的影响基本上为零。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.