Który z nich jest szybszy / lepszy?
Ten:
List<User> list = new List<User>();
User u;
foreach (string s in l)
{
u = new User();
u.Name = s;
list.Add(u);
}
Albo ten:
List<User> list = new List<User>();
foreach (string s in l)
{
User u = new User();
u.Name = s;
list.Add(u);
}
Moje umiejętności rozwijania początkujących mówią mi, że pierwsza jest lepsza, ale mój przyjaciel mówi mi, że się mylę, ale nie może podać dobrego powodu, dla którego druga jest lepsza.
Czy jest jakaś różnica w wydajności?
W każdym razie najlepszym sposobem byłoby użycie konstruktora, który przyjmuje nazwę ... lub, w przeciwnym razie, wykorzystanie notacji w nawiasach klamrowych:
foreach (string s in l) { list.Add(new User(s)); }
lub
foreach (string s in l) { list.Add(new User() { Name = s }); }
lub nawet lepiej, LINQ:
var list = l.Select( s => new User { Name = s});
Teraz, podczas gdy pierwszy przykład mógłby w niektórych przypadkach być niewyraźnie szybszy, drugi jest lepszy, ponieważ jest bardziej czytelny, a kompilator może odrzucić zmienną (i całkowicie ją pominąć), ponieważ nie jest używana poza
foreach
zakresem.źródło
Deklaracja nie powoduje wykonania żadnego kodu, więc nie jest to problem z wydajnością.
Drugie jest tym, co masz na myśli, i mniej prawdopodobne jest, że popełnisz głupi błąd, jeśli zrobisz to w drugi sposób, więc użyj tego. Zawsze staraj się deklarować zmienne w możliwie najmniejszym zakresie.
Poza tym lepszym sposobem jest użycie Linq:
List<User> users = l.Select(name => new User{ Name = name }).ToList();
źródło
Zawsze, gdy masz pytanie dotyczące wydajności, jedyną rzeczą do zrobienia jest pomiar - wykonaj pętlę wokół testu i zmień czas.
Aby odpowiedzieć na Twoje pytanie - bez mierzenia :-) lub patrzenia na wygenerowany ilasm - żadna różnica nie byłaby zauważalna w znaczącej liczbie iteracji i najdroższej operacji w Twoim kodzie, prawdopodobnie będzie to przypisanie użytkowników przez kilka zamówień wielkości, więc skoncentruj się na przejrzystości kodu (tak jak ogólnie powinieneś) i idź z 2.
Och, jest późno i myślę, że staram się tylko powiedzieć, że nie martw się o tego typu rzeczy ani nie daj się wciągnąć w takie szczegóły.
K.
źródło
Drugi jest lepszy. Masz zamiar mieć nowego użytkownika w każdej iteracji.
źródło
Technicznie rzecz biorąc, pierwszy przykład pozwoli zaoszczędzić kilka nanosekund, ponieważ ramka stosu nie będzie musiała być przenoszona, aby przydzielić nową zmienną, ale jest to tak mała ilość czasu procesora, że tego nie zauważysz, jeśli kompilator tego nie zrobi zoptymalizować każdą różnicę w dowolnym momencie.
źródło
W tym scenariuszu druga wersja jest lepsza.
Ogólnie rzecz biorąc, jeśli potrzebujesz tylko dostępu do wartości w treści iteracji, wybierz drugą wersję. Z drugiej strony, jeśli istnieje jakiś ostateczny stan, który zmienna będzie utrzymywać poza ciałem pętli, zadeklaruj, a następnie użyj pierwszej wersji.
źródło
Nie powinno być zauważalnej różnicy w wydajności.
źródło
Kolejne odniesienie, które wygląda jak powyżej:
http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/d43aaba5-a58b-4610-bea4-5bc5d6741f98
źródło
Poszedłem sprawdzić ten problem. Zaskakująco dowiedziałem się na moich brudnych testach, że druga opcja jest przez cały czas nawet nieco szybsza.
namespace Test { class Foreach { string[] names = new[] { "ABC", "MNL", "XYZ" }; void Method1() { List<User> list = new List<User>(); User u; foreach (string s in names) { u = new User(); u.Name = s; list.Add(u); } } void Method2() { List<User> list = new List<User>(); foreach (string s in names) { User u = new User(); u.Name = s; list.Add(u); } } } public class User { public string Name; } }
Sprawdziłem CIL, ale nie jest identyczny.
Przygotowałem więc coś, co chciałem być znacznie lepszym testem.
namespace Test { class Loop { public TimeSpan method1 = new TimeSpan(); public TimeSpan method2 = new TimeSpan(); Stopwatch sw = new Stopwatch(); public void Method1() { sw.Restart(); C c; C c1; C c2; C c3; C c4; int i = 1000; while (i-- > 0) { c = new C(); c1 = new C(); c2 = new C(); c3 = new C(); c4 = new C(); } sw.Stop(); method1 = method1.Add(sw.Elapsed); } public void Method2() { sw.Restart(); int i = 1000; while (i-- > 0) { var c = new C(); var c1 = new C(); var c2 = new C(); var c3 = new C(); var c4 = new C(); } sw.Stop(); method2 = method2.Add(sw.Elapsed); } } class C { } }
Również w tym przypadku druga metoda zawsze wygrywała, ale potem zweryfikowałem CIL, nie znajdując żadnej różnicy.
Nie jestem guru czytającym CIL, ale nie widzę problemu dekleracji. Jak już wspomniano, deklaracja nie jest alokacją, więc nie ma na niej żadnej utraty wydajności.
Test
namespace Test { class Foreach { string[] names = new[] { "ABC", "MNL", "XYZ" }; public TimeSpan method1 = new TimeSpan(); public TimeSpan method2 = new TimeSpan(); Stopwatch sw = new Stopwatch(); void Method1() { sw.Restart(); List<User> list = new List<User>(); User u; foreach (string s in names) { u = new User(); u.Name = s; list.Add(u); } sw.Stop(); method1 = method1.Add(sw.Elapsed); } void Method2() { sw.Restart(); List<User> list = new List<User>(); foreach (string s in names) { User u = new User(); u.Name = s; list.Add(u); } sw.Stop(); method2 = method2.Add(sw.Elapsed); } } public class User { public string Name; }
źródło