簡體   English   中英

在VB.NET,C#等中,單點規則是否會自動優化到代碼中?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM