public class MyClass
{
public object Prop1 { get; set; }
public object Prop2 { get; set; }
public object Prop3 { get; set; }
}
Załóżmy, że mam obiektu myObject
z MyClass
i muszę zresetować swoje właściwości, lepiej jest utworzyć nowy obiekt lub przypisać każdą właściwość? Załóżmy, że nie mam żadnego dodatkowego zastosowania ze starą instancją.
myObject = new MyClass();
lub
myObject.Prop1 = null;
myObject.Prop2 = null;
myObject.Prop3 = null;
c#
object-oriented
construction
Dzwony
źródło
źródło
Suppose I have an object myObject of MyClass and I need to reset its properties
- Jeśli konieczne jest zresetowanie właściwości obiektu lub przydatne jest modelowanie domeny problemowej, dlaczego nie stworzyćreset()
metody dla MyClass. Zobacz odpowiedź HarrisonPaine poniżejOdpowiedzi:
Tworzenie nowego obiektu jest zawsze lepsze, wtedy masz 1 miejsce do zainicjowania właściwości (konstruktora) i możesz go łatwo zaktualizować.
Wyobraź sobie, że dodajesz nową właściwość do klasy, wolisz zaktualizować konstruktor niż dodać nową metodę, która również ponownie inicjuje wszystkie właściwości.
Teraz są przypadki, w których możesz chcieć ponownie użyć obiektu, taki, w którym właściwość jest bardzo kosztowna w celu ponownej inicjalizacji i chcesz ją zachować. Byłby to jednak bardziej specjalistyczny specjalista i dysponowałbyś specjalnymi metodami ponownego inicjowania wszystkich innych właściwości. Nadal będziesz chciał stworzyć nowy obiekt czasami nawet w tej sytuacji.
źródło
myObject = new MyClass(oldObject);
. Chociaż oznaczałoby to dokładną kopię oryginalnego obiektu w nowej instancji.new MyClass(oldObject)
to najlepsze rozwiązanie w przypadkach, gdy inicjalizacja jest droga.Zdecydowanie wolisz stworzyć nowy obiekt w zdecydowanej większości przypadków. Problemy z ponownym przypisaniem wszystkich właściwości:
A
i klasaB
są zaliczonymi instancjami klasyC
, muszą wiedzieć, czy kiedykolwiek przejdą tę samą instancję, a jeśli tak, to czy druga nadal z niej korzysta. To ściśle łączy klasy, które w innym przypadku nie miałyby powodu.Fraction
klasę z licznikiem i mianownikiem i chciałeś wymusić, aby zawsze była zmniejszona (tj. Gcd licznika i mianownika wynosi 1). Nie da się tego zrobić dobrze, jeśli chcesz, aby ludzie mogli publicznie ustawić licznik i mianownik, ponieważ mogą przechodzić przez stan nieprawidłowy, aby przejść z jednego prawidłowego stanu do drugiego. Np. 1/2 (ważny) -> 2/2 (nieprawidłowy) -> 2/3 (ważny).To wszystkie dość znaczące problemy. A w zamian za dodatkową pracę, którą tworzysz, jest ... nic. Tworzenie instancji obiektów jest na ogół niezwykle tanie, więc korzyści związane z wydajnością prawie zawsze będą znikome.
Jak wspomniano w innej odpowiedzi, jedynym problemem, który może być istotnym problemem, jest to, czy twoja klasa wykona bardzo drogie prace przy budowie. Ale nawet w takim przypadku, aby ta technika zadziałała, będziesz musiał być w stanie oddzielić kosztowną część od właściwości, które resetujesz, dzięki czemu możesz zamiast tego użyć wzoru flyweight lub podobnego.
Na marginesie, niektóre z powyższych problemów można nieco złagodzić, nie używając setterów i zamiast tego mając
public Reset
w swojej klasie metodę, która przyjmuje takie same parametry jak konstruktor. Jeśli z jakiegoś powodu chciałbyś pójść tą drogą resetowania, prawdopodobnie byłby to o wiele lepszy sposób.Jednak dodatkowa złożoność i powtarzalność, które dodają, wraz z powyższymi punktami, których nie dotyczy, są nadal bardzo przekonującym argumentem przeciwko temu, szczególnie w porównaniu z nieistniejącymi korzyściami.
źródło
Biorąc pod uwagę bardzo ogólny przykład, trudno powiedzieć. Jeśli „resetowanie właściwości” ma sens semantyczny w przypadku domeny, bardziej sensowne będzie zadzwonienie do konsumenta z twojej klasy
Niż
NIGDY nie wymagałbym nawiązania połączenia z konsumentem z twojej klasy
Jeśli klasa reprezentuje coś, co można zresetować, powinna ujawnić tę funkcjonalność za pomocą
Reset()
metody, zamiast polegać na wywołaniu konstruktora lub ręcznym ustawieniu jego właściwości.źródło
Jak sugerują Harrison Paine i Brandin, ponownie użyłbym tego samego obiektu i rozłożyłbym parametry inicjalizacji właściwości w metodzie Reset:
źródło
Jeżeli zamierzone wzór Wykorzystanie dla klasy jest to, że pojedynczy właściciel będzie zachować odniesienie do każdej instancji, żaden inny kod będzie przechowywać kopie referencji, i to będzie bardzo często właściciele posiadają pętle, które muszą, wiele razy " wypełnij „pustą instancję, użyj jej tymczasowo i nigdy więcej jej nie potrzebujesz (powszechna klasa spełniająca takie kryterium
StringBuilder
), wówczas z punktu widzenia wydajności przydatne może być włączenie metody resetowania instancji w celu polubienia- nowy warunek. Taka optymalizacja prawdopodobnie nie będzie warta wiele, jeśli alternatywa wymagałaby jedynie utworzenia kilkuset instancji, ale koszt utworzenia milionów lub miliardów instancji obiektów może się sumować.W pokrewnej uwadze istnieje kilka wzorców, których można użyć dla metod, które muszą zwrócić dane w obiekcie:
Metoda tworzy nowy obiekt; zwraca referencję.
Metoda przyjmuje odwołanie do obiektu zmiennego i wypełnia go.
Metoda przyjmuje zmienną typu referencyjnego jako
ref
parametr i albo wykorzystuje istniejący obiekt, jeśli jest to odpowiednie, albo zmienia zmienną, aby zidentyfikować nowy obiekt.Pierwsze podejście jest często najłatwiejsze semantycznie. Drugi jest nieco niewygodny po stronie wywołującej, ale może zaoferować lepszą wydajność, jeśli dzwoniący często będzie mógł utworzyć jeden obiekt i użyć go tysiące razy. Trzecie podejście jest trochę niewygodne semantycznie, ale może być pomocne, jeśli metoda będzie musiała zwrócić dane w tablicy, a osoba dzwoniąca nie będzie znać wymaganego rozmiaru tablicy. Jeśli kod wywołujący zawiera jedyne odniesienie do tablicy, przepisanie tego odwołania z odwołaniem do większej tablicy będzie semantycznie równoważne po prostu powiększeniu tablicy (co jest pożądanym zachowaniem semantycznym). Chociaż
List<T>
w wielu przypadkach użycie może być lepsze niż użycie tablicy o ręcznie zmienionym rozmiarze, tablice struktur oferują lepszą semantykę i lepszą wydajność niż listy struktur.źródło
Myślę, że większości osób, które opowiadają się za tworzeniem nowego obiektu, brakuje krytycznego scenariusza: odśmiecanie (GC). GC może mieć prawdziwy wpływ na wydajność w aplikacjach, które tworzą wiele obiektów (np. Gry lub aplikacje naukowe).
Załóżmy, że mam drzewo wyrażeń reprezentujące wyrażenie matematyczne, w którym w węzłach wewnętrznych znajdują się węzły funkcyjne (ADD, SUB, MUL, DIV), a węzły liści są węzłami końcowymi (X, e, PI). Jeśli moja klasa węzłów ma metodę Evaluate (), prawdopodobnie będzie rekurencyjnie wywoływała dzieci i zbierała dane za pośrednictwem węzła Data. Przynajmniej wszystkie węzły liścia będą musiały utworzyć obiekt Data, a następnie będą mogły zostać ponownie wykorzystane podczas przechodzenia w górę drzewa, aż do oceny końcowej wartości.
Powiedzmy teraz, że mam tysiące tych drzew i jestem oceniany w pętli. Wszystkie te obiekty danych wywołają GC i spowodują duży spadek wydajności (do 40% utraty wykorzystania procesora dla niektórych uruchomień w mojej aplikacji - uruchomiłem profiler, aby uzyskać dane).
Możliwe rozwiązanie? Ponownie użyj tych obiektów danych i po prostu wywołaj na nich część .Reset () po ich użyciu. Węzły liścia nie będą już wywoływać „nowych danych ()”, będą wywoływać metodę Factory, która obsługuje cykl życia obiektu.
Wiem to, ponieważ mam aplikację, która dotknęła tego problemu i to go rozwiązało.
źródło