W twoim przypadku nie ma żadnej różnicy w funkcjonalności. Istnieje problem z ustaleniem, gdzie i jak wszystko zostanie zainicjalizowane. Jeśli wstawię inicjalizację do konstruktora, mam dwie duże zalety:
Wszystko zostało zainicjowane w jednym miejscu; Nie muszę polować na to, czy i gdzie to się skończy.
Jeśli chcę, mogę przekazywać argumenty do konstruktora prętów w oparciu o sposób ustawiania rzeczy. Jeśli inicjator jest poza konstruktorem, jestem znacznie bardziej ograniczony w tym, jak mogę zainicjować rzeczy.
Szczerze mówiąc, IDE pomaga trochę z nr 1 ... chociaż to nie szarpać mnie od kodu i po prostu patrząc na moje zajęcia rzadko są tak ogromne jak zrobić ponowne odkrycie rzeczy problem . Więc jeśli nie potrzebuję 2, równie dobrze mogę to zrobić w dowolny sposób, w zależności od projektu i nastroju. W przypadku większych projektów chciałbym mieć cały mój kod init w jednym miejscu.
Edit:
OK, najwyraźniej istnieje różnica między tymi dwoma. Ale przypadek, w którym ma to znaczenie, jest rzadkością.
Utworzyłem następujących klas:
class Program
{
public Program() { Console.WriteLine(this); }
static void Main(string[] args)
{
other p = new other();
Console.WriteLine(p);
Console.ReadLine();
}
}
class other : Program
{
string s1 = "Hello";
string s2;
public other() { s2 = "World"; }
public override string ToString() { return s1 + s2; }
}
Teraz, co uważam, że było nieco zaskakujące i nieoczekiwane (jeśli nie czytałeś # specyfikację C).
To co konstruktora klasy other
skompilowany.
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 29 (0x1d)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldstr "Hello"
IL_0006: stfld string ConsoleApplication1.other::s1
IL_000b: ldarg.0
IL_000c: call instance void ConsoleApplication1.Program::.ctor()
IL_0011: ldarg.0
IL_0012: ldstr "World"
IL_0017: stfld string ConsoleApplication1.other::s2
IL_001c: ret
} // end of method other::.ctor
Uwaga wezwanie do programowania :: konstruktor (konstruktora klasy bazowej) umieszczonej pomiędzy dwoma ldstr
/stfld
par (są co ustawić s1
i s2
). Znaczenie: kiedy konstruktor podstawowy działa, s2
nie został jeszcze ustawiony.
Program, w celach informacyjnych, wyprowadza następujące:
Hello
HelloWorld
ponieważ konstruktor programu, Console.WriteLine(obj)
nazywa obj.ToString()
, która (ponieważ obiekt jest już other
) był other::ToString()
. Ponieważ s2
nie zostało jeszcze ustalone, po raz pierwszy nie otrzymaliśmy "Świata". Jeśli robimy coś bardziej podatnego na błędy niż zwykłe drukowanie, może to spowodować poważne problemy.
To jest brzydki przykład, mający być patologicznym przypadkiem. Ale jest to doskonały argument przeciwko wywoływaniu funkcji wirtualnych w twoim konstruktorze. Bez tego tylko złamanie tego nie byłoby możliwe. To jedyny czas, w którym naprawdę musisz się martwić o różnicę: kiedy twój konstruktor klasy podstawowej wywołuje metody wirtualne, które przesłoniłeś, które polegają na wartościach wszystkich pól ustawianych w konstruktorze. To dość wąskie okno z breakability, ale tak.
Możliwy duplikat: http://stackoverflow.com/questions/4219759/create-an-object-in-the-constructor-or-at-top-the-class lub: http: // stackoverflow. com/questions/298183/c-member-variable-initialization-best-practice –
Dzięki za złapanie dupków, Yodan –