Wywołanie destruktora

0

Witam. Mam taki problem, ponieważ instrukcje z destruktora nie są wypisywane w konsoli. Co zrobić, aby w konsoli zobaczyć tekst podany w destruktorze? Jeśli to ma jakieś znaczenie to korzystam z Visual Studio na MacOS.
screenshot-20220706171244.png

2

A po co chcesz zrobić coś takiego? Poleganie na garbage kolektorze żeby wywołać jakąś logikę jest... wątpliwy.

1
Riddle napisał(a):

A po co chcesz zrobić coś takiego?

Próbuje ogólnie znaleźć zastosowanie destruktora i zobaczyć jak działa

0
Maciek_SK8 napisał(a):
Riddle napisał(a):

A po co chcesz zrobić coś takiego?

Próbuje ogólnie znaleźć zastosowanie destruktora i zobaczyć jak działa

No to jego zastosowanie raczej jest ograniczone.

Nie można ich wywołać "po prostu", są wołane w momencie w którym nie ma już sposobu żeby skorzystać z obiektu, czyli np kiedy wszystkie referencje do niego już znikną.

0

Czekaj, czekaj, To C# ma destruktory? Destruktory są zwykle dla obiektów ręcznie zarządzanych, ewentualnie zarządzanych przez liczenie referencji. No ale .NOT ma chyba bardzie rozbudowany system sprzątania śmieci więc wtedy destruktor może być wywołanykiedyś później w skrajnym wypadku nigdy bo program się skończył,

0
KamilAdam napisał(a):

Czekaj, czekaj, To C# ma destruktory? Destruktory są zwykle dla obiektów ręcznie zarządzanych, ewentualnie zarządzanych przez liczenie referencji. No ale .NOT ma chyba bardzie rozbudowany system sprzątania śmieci więc wtedy destruktor może być wywołanykiedyś później w skrajnym wypadku nigdy bo program się skończył,

W c# destruktory są wołane przez garbage-collector kiedy już nie ma żadnej referencji do obiektu. Przy okazji destruktory z tego co pamiętam wołają Finalize.

Tak czy tak, ich użyteczność jest raczej niska.

Jeśli chcesz ogarniać co ma się stać z otwartymi zasobami to lepiej użyć bloku using np.

2
Maciek_SK8 napisał(a):
Riddle napisał(a):

A po co chcesz zrobić coś takiego?

Próbuje ogólnie znaleźć zastosowanie destruktora i zobaczyć jak działa

Nie wiem jak w .NET, ale w JVM od lat mówi się że destruktorów (zwanych tam finalizerami) nie należy dotykać(używać/nadpisywać) . Pamietam dwa powody:

  • Nie mamy pewności kiedy destruktor zostanie wykonany
  • umieszczanie kodu w destruktorze spowalnia sprzątanie sterty
0
Riddle napisał(a):
KamilAdam napisał(a):

Czekaj, czekaj, To C# ma destruktory? Destruktory są zwykle dla obiektów ręcznie zarządzanych, ewentualnie zarządzanych przez liczenie referencji. No ale .NOT ma chyba bardzie rozbudowany system sprzątania śmieci więc wtedy destruktor może być wywołanykiedyś później w skrajnym wypadku nigdy bo program się skończył,

W c# destruktory są wołane przez garbage-collector kiedy już nie ma żadnej referencji do obiektu. Przy okazji destruktory z tego co pamiętam wołają Finalize.

Tak czy tak, ich użyteczność jest raczej niska.

Jeśli chcesz ogarniać co ma się stać z otwartymi zasobami to lepiej użyć bloku using np.

Czyli nie warto używać destruktora na podstawowym poziomie?

1
Maciek_SK8 napisał(a):
Riddle napisał(a):
KamilAdam napisał(a):

Czekaj, czekaj, To C# ma destruktory? Destruktory są zwykle dla obiektów ręcznie zarządzanych, ewentualnie zarządzanych przez liczenie referencji. No ale .NOT ma chyba bardzie rozbudowany system sprzątania śmieci więc wtedy destruktor może być wywołanykiedyś później w skrajnym wypadku nigdy bo program się skończył,

W c# destruktory są wołane przez garbage-collector kiedy już nie ma żadnej referencji do obiektu. Przy okazji destruktory z tego co pamiętam wołają Finalize.

Tak czy tak, ich użyteczność jest raczej niska.

Jeśli chcesz ogarniać co ma się stać z otwartymi zasobami to lepiej użyć bloku using np.

Czyli nie warto używać destruktora na podstawowym poziomie?

Raczej nie.

0
Maciek_SK8 napisał(a):
Riddle napisał(a):

A po co chcesz zrobić coś takiego?

Próbuje ogólnie znaleźć zastosowanie destruktora i zobaczyć jak działa

Nie jest to właściwie destruktor (jak w C++), bo nie jest deterministyczny ... lepszym słowem, choć nie idealnym, jest finalizer.
"Obserwacja" tego jest dośc trudna, bo zależy od odśmiecacza

1
Riddle napisał(a):

Jeśli chcesz ogarniać co ma się stać z otwartymi zasobami to lepiej użyć bloku using np.

To ważne, z ważnym ALE.
Użycie using nie wpływa za specjalnie na prawdziwą destrukcję (pozbawiony referencji będzie się gdzieś plątał aż GC go usunie), ale o ile klasa implementuje IDisposable to wykonanie metody Dispose.

Fakt, to ma implementować przygotowanie do śmierci, ale na poziomie języka to jest aż i tylko jeszcze jeden interfejs i jeszcze inne metoda normalnych, ciągle żywych obiektów. Powinno to być zwolnie zasobów, które instancja obiektu posiada.
Takie spisanie testamentu / darowizna przed śmiercią

Java wprowadziła analogiczny pomysł później, nazywa try with resources, a implementowanym interfejsem ma być java.lang.AutoCloseable
O ile historycznie kopiowanie zachodziło Java -> C#, to tutaj jedno z lepszych kopiowań w odwrotną stronę.

0
ZrobieDobrze napisał(a):
Riddle napisał(a):

Jeśli chcesz ogarniać co ma się stać z otwartymi zasobami to lepiej użyć bloku using np.

To ważne, z ważnym ALE.
Użycie using nie wpływa za specjalnie na prawdziwą destrukcję (pozbawiony referencji będzie się gdzieś plątał aż GC go usunie), ale o ile klasa implementuje IDisposable to wykonanie metody Dispose.

Fakt, to ma implementować przygotowanie do śmierci, ale na poziomie języka to jest aż i tylko jeszcze jeden interfejs i jeszcze inne metoda normalnych, ciągle żywych obiektów. Powinno to być zwolnie zasobów, które instancja obiektu posiada.
Takie spisanie testamentu / darowizna przed śmiercią

Java wprowadziła analogiczny pomysł później, nazywa try with resources, a implementowanym interfejsem ma być java.lang.AutoCloseable
O ile historycznie kopiowanie zachodziło Java -> C#, to tutaj jedno z lepszych kopiowań w odwrotną stronę.

using nie ma na celu żadnego udawania "przygotowania do smierci", tylko to po prostu konstrukt języka wywołujący operację symetryczną, typu otwarcie i zamknięcie pliku, założenie locka i ściągnięcie locka. Nie ma nic wspólnego z destruktorami ani gargabe-collectorem.

3

@Maciek_SK8:

Czyli nie warto używać destruktora na podstawowym poziomie?

Na żadnym nie warto tego używać jako coś normalnego.

To jest prędzej coś, co może się w bardzo specyficznych i pojedynczych przypadkach przydać

czyli czytaj to jako: raz na kilka lat robiąc coś nietypowego.

0
1a2b3c4d5e napisał(a):

@Maciek_SK8:

Czyli nie warto używać destruktora na podstawowym poziomie?

Na żadnym nie warto tego używać jako coś normalnego.

To jest prędzej coś, co może się w bardzo specyficznych i pojedynczych przypadkach przydać

czyli czytaj to jako: raz na kilka lat robiąc coś nietypowego.

Okok dzięki bardzo za odpowiedz

1

Wywołaj GC:

klasa = null;
GC.Collect();
GC.WaitForPendingFinalizers();
1

Jak już, to najlepiej GC.Collect(2, GCCollectionMode.Forced);, aby zamieść wszystkie generacje śmieci i wymusić uruchomienie.

Podstawowa różnica jest taka, że w C++ to programista decyduje o momencie zniszczenia obiektu, a w C# to system o tym decyduje. Jeżeli w klasie definiujesz coś, co nie jest tylko danymi w pamięci (np. otwarcie pliku, otwarcie gniazd sieciowego itp.), to zaimplementuj "destruktor" w metodzie Dispose, klasa musi implementować interfejs IDisposable, a tworzenie obiektu powinno być z użyciem using.

Można mniej więcej coś takiego, można nawet zabezpieczyć przed przypadkowym wywołaniem czegoś po uruchomieniu Dispose, gdyby z jakiś powodów nie można było użyć z wykorzystaniem using. Dla pewności można dodać wywołanie Dispose w destruktorze.


class SomeClass : IDisposable
{
    bool IsDisposed;

    public SomeClass()
    {
        IsDisposed = false;
    }

    ~SomeClass()
    {
        Dispose();
    }

    public void SomeWork()
    {
        if (IsDisposed) throw new Exception("SomeClass object is disposed");
        SomeCode();
    }

    public void Dispose()
    {
        if (!IsDisposed)
        {
            IsDisposed = true;
            SomeDisposeCode();
        }
    }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1