2013-06-11 9 views
5

Jeśli mamoptymalizacji kompilator po powrocie ciągi

private string Foo(string decrypted) 
{ 
    return decrypted.Substring(blah); 
} 

i

private string Foo(string decrypted) 
{ 
    string s = decrypted.Substring(blah); 
    return s; 
} 

Czy to jest to samo? Czy kompilator jest w stanie usunąć s?

Jak o

private string Foo(string decrypted) 
{ 
    string s = decrypted.Substring(blah); 
    string t = s; 
    return t; 
} 

?

Dzięki.

+2

Dlaczego to ma znaczenie? 'string' jest typem referencyjnym, więc nawet jeśli nie byłby zoptymalizowany, to w najgorszym wypadku byłyby dwie dodatkowe kopie o wielkości słowa. To orzeszki ziemne. – delnan

+1

to nie ma znaczenia, jest to O (1) różnica czasu Pierwsza jest zwykle bardziej czytelna, więc użyj tego. Z wyjątkiem sytuacji, gdy drugi jest bardziej czytelny, użyj tego –

Odpowiedz

1

Wydaje mi się, że pytanie brzmi: "czy obsługa kompilatora C# named return value optimization (NRVO)?"

To rozsądne pytanie, jak przypuszczam, ale jak w przypadku delnan points out, nie jest to szczególnie istotne ze względu na fakt, że łańcuchy w języku C# są typami odniesienia. Jeśli jesteś programistą C++, możesz myśleć o typach referencyjnych jako zasadniczo równoważnych wskaźnikom. Więc jeśli zwracasz ciąg znaków według wartości, naprawdę zwracasz tylko wartość, a nie sam obiekt. To tak, jakbyś zwracał adres wskaźnika według wartości. Kopia całego obiektu typu string nie musi być wykonana, więc optymalizacja zyskuje bardzo niewiele. Jedynym powodem, dla którego potrzebujesz NRVO, jest uniknięcie uderzeń wydajności dużej i kosztownej kopii, ale kopiowanie wskaźnika/odniesienia nie jest drogie.

Jeśli jednak podano inny przykład, w którym użyto typu wartości, a nie typu odniesienia (np. Dużej struktury), może nastąpić znaczna poprawa wydajności, którą można uzyskać poprzez wdrożenie NRVO. Niestety, nawet w tym przypadku, nie wierzę, że kompilator C# to robi. Przypuszczam, że JITer może; Nie mogę powiedzieć na pewno. (A jeśli nie zostanie to zrobione teraz, zawsze może być dodane w przyszłych wersjach. Chociaż takie duże struktury występują tylko rzadko w kodzie C#, więc jest mało prawdopodobne, że jest na szczycie listy celów zespołu zespołu wykonawców.)

Aby uzyskać więcej informacji, przeczytaj artykuł Jona Skeeta na temat References and Values w C#.

4

Byłem ciekawy, więc wypróbowałem go (używając LINQPad 4 z optymalizacją). To jest to, co mam:

private string Foo(string decrypted) 
{ 
    return decrypted.Substring(0); 
} 
Foo: 
IL_0000: ldarg.1  
IL_0001: ldc.i4.0  
IL_0002: callvirt System.String.Substring 
IL_0007: ret   

private string Foo(string decrypted) 
{ 
    string s = decrypted.Substring(0); 
    return s; 
} 
Foo: 
IL_0000: ldarg.1  
IL_0001: ldc.i4.0  
IL_0002: callvirt System.String.Substring 
IL_0007: stloc.0  // s 
IL_0008: ldloc.0  // s 
IL_0009: ret  

private string Foo(string decrypted) 
{ 
    string s = decrypted.Substring(0); 
    string t = s; 
    return t; 
} 
Foo: 
IL_0000: ldarg.1  
IL_0001: ldc.i4.0  
IL_0002: callvirt System.String.Substring 
IL_0007: stloc.0  // s 
IL_0008: ldloc.0  // s 
IL_0009: stloc.1  // t 
IL_000A: ldloc.1  // t 
IL_000B: ret  

Wydaje się, że kompilator nie zoptymalizować dala s lub t jednak podejrzewam interpreter JIT będzie.

+0

Czy jest to tryb wydania z optymalizacją? (tryb debugowania na pewno je opuści) – viraptor

+0

@viraptor Włączyłem optymalizacje w LINQPad, tak. Według LINQPad jest to "odpowiednik trybu" Release "Visual Studio i wyłącza śledzenie wykonania na żywo" –

+1

Wydanie kompilacji z Visual Studio * zdecydowanie * usunięcie dodatkowej zmiennej. (Właśnie to testowałem) Wydaje się więc, że to, co mówi Linqpad, nie jest prawdą. W Reflectorze po prostu pokazuje: 'return decrypted.Substring (0);' –