简体   繁体   English

在VB.NET,C#等中,单点规则是否会自动优化到代码中?

[英]In VB.NET, C#, etc., does the one-dot rule automatically get optimized into the code?

In VB.NET, C#, etc., something like this wouldn't get optimized, would it? 在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)

In ECMA-type languages at least, this is a good habit to be in to minimize how many times it goes to a , then goes to its B field/property, then finally goes to its C field/property. 至少在ECMA类型的语言中,这是一个好习惯,要尽量减少它进入a ,然后转到其B字段/属性,最后到其C字段/属性。 I would think that is normally the rule of thumb in any typical object-oriented or procedural language, except where there's at least a pretty solid expectation that it's just going to get optimized like that by the compiler/jit/etc. 我认为这通常是任何典型的面向对象或过程语言中的经验法则,除非至少有一个明确的期望,那就是它将像编译器/ jit / etc那样得到优化。 anyway. 无论如何。 How is this handled in typical .NET, particularly for VB.NET and C#? 在典型的.NET(特别是VB.NET和C#)中如何处理?

This, for instance, doesn't seem to mention the one-dot rule, at least pertaining to either of those two languages: https://msdn.microsoft.com/en-us/library/ms973839.aspx . 例如,这似乎没有提到单点规则,至少与这两种语言之一有关: https : //msdn.microsoft.com/zh-cn/library/ms973839.aspx On the other hand, I would be very surprised if it did this in general for properties, since those are effectively methods. 另一方面,如果对属性进行一般设置,我会感到非常惊讶,因为它们是有效的方法。 It would seem to make more sense if it did this if and only if they were fields are possibly even completely trivial properties. 如果这样做,并且仅当它们是字段,甚至可能是完全无关紧要的属性时,这样做似乎更有意义。

Okay, I went ahead and tried it out for curiosity's sake. 好吧,出于好奇,我继续尝试了一下。

Given the following classes: 给定以下类别:

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" } } };
}

And the following method: 和以下方法:

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 reports the IL emitted for main in release mode as 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 

So it looks like you do save some callvirts by not drilling through the properties each time. 因此,看起来您确实通过不每次都钻取属性来保存了一些callvirt。 Whether this has any measurable impact on the JIT at run-time is not something I can answer, but it does appear to leave a smaller IL footprint. 我无法回答这是否会对运行时的JIT产生任何可衡量的影响,但是它确实留下了较小的IL占用空间。

I suspect it has basically zero impact on run-time performance. 我怀疑它对运行时性能的影响基本上为零。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM