0

Помогите реализовать деструктор – не пойму, как сослаться на него:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Laba6
{
class EngMoney
{
    private float funt, pens, shilling,funt1,pens1,shilling1,nomer;
    private bool vuvod;



    public EngMoney(float funt, float pens, float shilling, float funt1, float pens1, float 
 shilling1, int nomer)
    {
        if (nomer == 1)
        {
            this.funt = funt + funt1;
            this.pens = pens + pens1;
            this.shilling = shilling+shilling1;
        }
        if (nomer == 2)
        {
            this.funt = funt - funt1;
            this.pens = pens - pens1;
            this.shilling = shilling - shilling1;
        }
        if (nomer == 3)
        {
            this.funt = funt * funt1;
            this.pens = pens * pens1;
            this.shilling = shilling * shilling1;
        }
        if (nomer == 4)
        {
            this.funt = funt / funt1;
            this.pens = pens / pens1;
            this.shilling = shilling / shilling1;
        }
        if (nomer == 5)
        {
            shilling = funt * 12 * 20;
            shilling1 = funt1 * 12 * 20;
            if (shilling > shilling1)
            {
                vuvod = false;
            }
            if (shilling < shilling1)
            {
                vuvod = true;
            }
        }
        this.funt1 = funt1;
        this.pens1 = pens1;
        this.shilling1 = shilling1;
        this.nomer = nomer;

    }

    public void Print()
    {

        if (nomer == 5)
        {
            if (vuvod == false)
            {
                Console.WriteLine("Первая сумма больше");
            }
            if (vuvod == true)
            {
                Console.WriteLine("Вторая сумма больше первой");
            }
            EngMoney();

        }
        else
        {
            Console.WriteLine("funt: " + funt);
            Console.WriteLine("pens :" + pens);
            Console.WriteLine("shilling: " + shilling);
        }
    }
    ~EngMoney()
    {
        Console.Beep();
        Console.WriteLine("Disposed");
    }
}
class Program
{
    public static float f, p, s,f1,p1,s1;
    public static int nomer;

    static void Main(string[] args)
    {
        Console.WriteLine("Ввод первой суммы");
        Console.WriteLine("Введите фунты: ");
        f = float.Parse(Console.ReadLine());
        Console.WriteLine("Введите пенсы: ");
        p = float.Parse(Console.ReadLine());
        Console.WriteLine("Введите шилинги: ");
        s = float.Parse(Console.ReadLine());
        Console.WriteLine("Ввод второй суммы");
        Console.WriteLine("Введите фунты: ");
        f1 = float.Parse(Console.ReadLine());
        Console.WriteLine("Введите пенсы: ");
        p1 = float.Parse(Console.ReadLine());
        Console.WriteLine("Введите шилинги: ");
        s1 = float.Parse(Console.ReadLine());
        Console.WriteLine("Выберите действие:");
        Console.WriteLine("1. Сложение");
        Console.WriteLine("2. Вычитание");
        Console.WriteLine("3. Умножение");
        Console.WriteLine("4. Деление");
        Console.WriteLine("5. Сравнение");
        nomer = int.Parse(Console.ReadLine());
        EngMoney newValue = new EngMoney(f, p, s, f1, p1, s1,nomer);
        newValue.Print();
        Console.ReadLine();
    }

}
}
MobiDevices
  • 7,309
Doctor Zlo
  • 46
  • 6
  • 3
    В C# это не деструктор, а финализер, вызов финализера - на усмотрение Garbage Collector. Все что вам нужно - это посмотреть примеры реализации и унаследовать IDisposable интерфейс. – aepot Jun 09 '20 at 09:34
  • 1
    Я смотрю на ваш класс и не пойму, зачем вам вообще деструктор? Вы не используете неуправляемые ресурсы и не создаете IDisposable классы. Память почистит GC автоматически, как только ссылка на объект будет забыта, но не сразу, а только когда сам соизволит это сделать. Там много внутри всяких оптимизаций, нацеленных на то, чтобы не подтормаживать ваше приложение при сборке мусора. – aepot Jun 09 '20 at 10:23
  • По заданию требуется добавить деструктор, я тоже не особо понимаю зачем он здесь нужен ведь есть автоматическая очистка неиспользуемых ресурсов. – Doctor Zlo Jun 09 '20 at 10:29
  • Перед GC.Collect() надо обнулить все ссылки на объект, иначе он не будет собран. – aepot Jun 09 '20 at 11:53
  • 2
    Если по заданию на c# требуется добавить деструктор, то решением будет ответ, что добавить деструктор не возможно, потому что их не бывает в c#. Ну заодно неплохо добавить информацию, что 1) память неиспользуемых объектов в c# освобождает сборщик мусора 2) для высвобождения управляемых ресурсов используется реализация интерфейса IDisposable 3) для высвобождения неуправляемых используется оболочки SafeHandle 4) если по каким-то объективным причинам SafeHandle не подходит, только тогда понадобиться реализовать финализатор. 3 и 4 вряд ли входит в повседневную практику 99% программистов c# – 4per Jun 09 '20 at 12:34
  • https://docs.microsoft.com/ru-ru/dotnet/standard/garbage-collection/unmanaged https://ru.stackoverflow.com/questions/486696/%D0%9A%D0%B0%D0%BA-%D0%B8-%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0-%D0%BD%D1%83%D0%B6%D0%BD%D0%BE-%D0%B8%D0%BC%D0%BF%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-idisposable – 4per Jun 09 '20 at 12:34
  • Вероятнее всего, что это задание с подвохом. Поддерживаю 4per. – Andrew Stop_RU_war_in_UA Jun 09 '20 at 12:53
  • 2
    Финализатор для EngMoney не вызовется до тех пор, пока вы не покинете метод Main (тот метод, где вы объявили переменную newValue). То есть, как минимум, надо выделить отдельный метод, в котором использовать EngMoney, и вызывать этот метод из Main. Но в любом случае, это не достаточноые условия. Как писали выше, возможно надо вызывать методы GC. – Uranus Jun 09 '20 at 12:56

1 Answers1

3

В C# это не деструктор, а финализер, вызов финализера - на усмотрение Garbage Collector. Все что вам нужно - это посмотреть примеры реализации и унаследовать IDisposable интерфейс.

Дополню комментарии выше примером. Просто в IDisposable финализатор есть, и программист его как бы не использует, то есть финализатор предназначен для GC, который может вызвать его, может не вызвать. И это вызывало километровые ленты обсуждений на гитхабе, нет ясности и конкретности в том, будет вызван финализатор, или нет. И есть конкретный ответ: "Финализатор обязательно будет вызван, но это не точно.", вот например неплохой блог пост на эту тему.

Я написал небольшой пример, который все-таки создает условия для вызова финализатора.

public class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("[main] Constructing");
        MyDisposable m = new MyDisposable(0);
        new MyDisposable(1);
        Console.WriteLine("[main] Disposing [object 0]");
        m.Dispose();
        Console.WriteLine("[main] GC Collecting");
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.WriteLine("[main] Done");
        Console.ReadKey();
    }
}

public class MyDisposable : IDisposable { private int _id;

public MyDisposable(int id)
{
    _id = id;
    Console.WriteLine($&quot;[object {_id}] Constructed&quot;);
}

private bool disposed = false;

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    if (!disposed)
    {
        if (disposing)
        {
            Console.WriteLine($&quot;[object {_id}] Disposing by Dispose()&quot;);
        }
        else
        {
            Console.WriteLine($&quot;[object {_id}] Disposing by ~Finalizer&quot;);
        }
        Console.WriteLine($&quot;[object {_id}] Disposed&quot;);
        disposed = true;
    }
    else
        Console.WriteLine($&quot;[object {_id}] Already disposed!&quot;);
}

~MyDisposable()
{
    Dispose(false);
}

}

А вывод в консоль вот такой

[main] Constructing
[object 0] Constructed
[object 1] Constructed
[main] Disposing [object 0]
[object 0] Disposing by Dispose()
[object 0] Disposed
[main] GC Collecting
[object 1] Disposing by ~Finalizer
[object 1] Disposed
[main] Done

Если же созданный объект был записан в переменную-ссылку, то чтобы его собрать, нужно покинуть метод, где он был по этой ссылке доступен.

Другими словами, если хочется гарантий, что объект будет уничтожен вовремя и правильно, лучше вызвать Dispose() вручную. А GC вас прикроет, дернет финализатор потеряного объекта, если вы где-то ошиблись и забыли прибрать за собой неуправляемые ресурсы.

aepot
  • 49,560
  • @Uranus говорил про другой код, там до конца Main() остаётся ссылка на объект в области видимости. У вас ссылка теряется сразу после конструирования или ещё раньше. Так что не очевидно почему GC до него не добрался. – 4per Jun 09 '20 at 13:20
  • @4per я уже изменил пример. И теперь все работает вполне определенным и ожидаемым образом. – aepot Jun 09 '20 at 13:21