Правильное выполнение IDisposable

В моих классах я реализую IDisposable следующим образом:

public class User : IDisposable
{
    public int id { get; protected set; }
    public string name { get; protected set; }
    public string pass { get; protected set; }

    public User(int UserID)
    {
        id = UserID;
    }
    public User(string Username, string Password)
    {
        name = Username;
        pass = Password;
    }

    // Other functions go here...

    public void Dispose()
    {
        // Clear all property values that maybe have been set
        // when the class was instantiated
        id = 0;
        name = String.Empty;
        pass = String.Empty;
    }
}

В VS2012 мой анализ кода говорит, что он правильно реализует IDisposable, но я не уверен, что я сделал здесь неправильно.
Точный текст выглядит следующим образом:

CA1063 Правильно выполните IDisposable. Предоставьте переопределяемую реализацию Dispose (bool) в "Пользователь" или отметьте тип как запечатанный. Вызов Dispose (false) должен только очищать собственные ресурсы. Вызов Dispose (true) должен очищать как управляемые, так и собственные ресурсы. stman User.cs 10

Для справки: CA1063: правильно реализовать IDisposable

Я прочитал эту страницу, но, боюсь, я не совсем понимаю, что нужно делать здесь.

Если кто-нибудь может объяснить в более ламинарных терминах, что проблема и/или как IDisposable должен быть реализован, это действительно поможет!

Ответ 1

Это будет правильная реализация, хотя я не вижу ничего, что вам нужно было бы использовать в коде, который вы опубликовали. Вам нужно всего лишь реализовать IDisposable, когда:

  • У вас есть неуправляемые ресурсы.
  • Вы держитесь за ссылки на вещи, которые сами по себе являются доступными.

Ничего в коде, который вы опубликовали, не требуется.

public class User : IDisposable
{
    public int id { get; protected set; }
    public string name { get; protected set; }
    public string pass { get; protected set; }

    public User(int userID)
    {
        id = userID;
    }
    public User(string Username, string Password)
    {
        name = Username;
        pass = Password;
    }

    // Other functions go here...

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing) 
        {
            // free managed resources
        }
        // free native resources if there are any.
    }

}

Ответ 2

Прежде всего, вам не нужно "очищать" string и int - они будут автоматически улавливаться сборщиком мусора. Единственное, что нужно очистить в Dispose, - это неуправляемые ресурсы или управляемые источники, которые реализуют IDisposable.

Однако, полагая, что это всего лишь учебное упражнение, рекомендуемым способом реализации IDisposable является добавление "защитного ключа" для обеспечения того, чтобы любые ресурсы не удалялись дважды:

public void Dispose()
{
    Dispose(true);

    // Use SupressFinalize in case a subclass 
    // of this type implements a finalizer.
    GC.SuppressFinalize(this);   
}
protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing) 
        {
            // Clear all property values that maybe have been set
            // when the class was instantiated
            id = 0;
            name = String.Empty;
            pass = String.Empty;
        }

        // Indicate that the instance has been disposed.
        _disposed = true;   
    }
}

Ответ 3

В следующем примере показана общая передовая практика реализации интерфейса IDisposable. Ссылка

Имейте в виду, что вам нужен деструктор (финализатор), только если у вас есть неуправляемые ресурсы в вашем классе. И если вы добавите деструктор, вы должны подавить Finalization в Dispose, иначе это приведет к тому, что ваши объекты будут находиться в памяти для двух циклов мусора (Примечание: Читать как работает финализация). Ниже приведен пример всего выше.

public class DisposeExample
{
    // A base class that implements IDisposable. 
    // By implementing IDisposable, you are announcing that 
    // instances of this type allocate scarce resources. 
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource. 
        private IntPtr handle;
        // Other managed resource this class uses. 
        private Component component = new Component();
        // Track whether Dispose has been called. 
        private bool disposed = false;

        // The class constructor. 
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable. 
        // Do not make this method virtual. 
        // A derived class should not be able to override this method. 
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method. 
            // Therefore, you should call GC.SupressFinalize to 
            // take this object off the finalization queue 
            // and prevent finalization code for this object 
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios. 
        // If disposing equals true, the method has been called directly 
        // or indirectly by a user code. Managed and unmanaged resources 
        // can be disposed. 
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed. 
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here. 
                // If disposing is false, 
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;

            }
        }

        // Use interop to call the method necessary 
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code. 
        // This destructor will run only if the Dispose method 
        // does not get called. 
        // It gives your base class the opportunity to finalize. 
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here. 
            // Calling Dispose(false) is optimal in terms of 
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create 
        // and use the MyResource object.
    }
}

Ответ 4

IDisposable существует, чтобы предоставить вам средства для очистки неуправляемых ресурсов, которые не будут автоматически очищены сборщиком мусора.

Все ресурсы, которые вы очищаете, являются управляемыми ресурсами, и поэтому ваш метод Dispose ничего не выполняет. Ваш класс не должен реализовывать IDisposable вообще. Сборщик мусора позаботится обо всех этих полях как раз сам по себе.

Ответ 5

Вам нужно использовать Одноразовый шаблон:

private bool _disposed = false;

protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing)
        {
            // Dispose any managed objects
            // ...
        }

        // Now disposed of any unmanaged objects
        // ...

        _disposed = true;
    }
}

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

// Destructor
~YourClassName()
{
    Dispose(false);
}

Ответ 6

Вам не нужно, чтобы ваш пользовательский класс был IDisposable, поскольку класс не получает никаких не управляемых ресурсов (файл, подключение к базе данных и т.д.). Обычно мы отмечаем классы как IDisposable, если у них есть хотя бы одно поле IDisposable или/и свойство. При реализации IDisposable лучше поместите его в соответствии с типичной схемой Microsoft:

public class User: IDisposable {
  ...
  protected virtual void Dispose(Boolean disposing) {
    if (disposing) {
      // There no need to set zero empty values to fields 
      // id = 0;
      // name = String.Empty;
      // pass = String.Empty;

      //TODO: free your true resources here (usually IDisposable fields)
    }
  }

  public void Dispose() {
    Dispose(true);

    GC.SuppressFinalize(this);
  } 
}

Ответ 7

Idisposable реализуется всякий раз, когда вам нужна детерминированная (подтвержденная) сборка мусора.

class Users : IDisposable
    {
        ~Users()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
            // This method will remove current object from garbage collector queue 
            // and stop calling finilize method twice 
        }    

        public void Dispose(bool disposer)
        {
            if (disposer)
            {
                // dispose the managed objects
            }
            // dispose the unmanaged objects
        }
    }

При создании и использовании класса Users используйте блок "using", чтобы избежать явного вызова метода dispose:

using (Users _user = new Users())
            {
                // do user related work
            }

конец используемого блока. Созданный объект Пользователи будут удалены неявным вызовом метода dispose.