Подтвердить что ты не робот

Можно ли принудительно использовать "использование" для одноразовых классов?

Мне нужно принудительно использовать "использование" для размещения нового экземпляра класса.

public class MyClass : IDisposable
{
   ...
}

using(MyClass obj = new MyClass()) // Force to use "using"
{
}
4b9b3361

Ответ 1

Тот факт, что вам нужно убедиться, что объект расположен, указывает на дефект дизайна. Это прекрасно, если утилизация - вежливая или эффективная вещь, но она не должна быть семантически необходимой.

Невозможно обеспечить, чтобы объект был удален с помощью инструкции using. Однако то, что вы можете сделать, это поддерживать флаг в объекте, который указывает, был ли объект удален или нет, а затем написать финализатор, который проверяет этот флаг. Если финализатор обнаруживает, что объект не был удален, вы можете иметь финализатор, скажем, завершить процесс с помощью failfast. То есть так сильно накажут пользователя, который пренебрег распоряжением объектом, который они вынуждены либо исправить свою ошибку, либо прекратить использовать ваш объект.

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

Ответ 2

Это уродливо, но вы можете сделать что-то вроде этого:

    public sealed class DisposableClass : IDisposable
    {
        private DisposableClass()
        {

        }

        public void Dispose()
        {
            //Dispose...
        }

        public static void DoSomething(Action<DisposableClass> doSomething)
        {
            using (var disposable = new DisposableClass())
            {
                doSomething(disposable);
            }
        }
    }

Ответ 3

Вы можете написать свое собственное предупреждение/ошибку с помощью системы Roslyn. Ваш DiagnosticAnalyzer будет проверять все вызовы конструктора, чтобы узнать, был ли ваш класс построен или нет, и если вы находитесь в инструкции using или нет.

Сообщенная диагностика может быть установлена ​​на "Серьезность ошибки" и может быть помечена как неконфигурируемая, что означает, что никто не может понизить ее до предупреждения или информации.

Кроме того, если вы разрабатываете библиотеку Nuget, вы можете отправить свой анализатор как зависимость от разработки и добавить его в качестве пакета анализатора nuget. Это приведет к тому, что все ваши пользователи будут вынуждены распоряжаться вашим классом. Эта упаковка называется "библиотекой, поддерживающей код" .

Обратите внимание, что теоретически это может быть сделано и с помощью библиотеки сторонних аналитиков (например, FxCop), но существует множество реализаций IDisposable, которые не обязательно должны быть удалены, например MemoryStream, чья Dispose не делает много, поэтому эти правила либо имеют некоторые механизмы с белым списком, либо сообщают о ложных срабатываниях.

Ответ 4

Оператор using является сокращением, которое преобразует компилятор из:

(using DisposableObject d = new DisposableObject()){}

в

DisposableObject d = new DisposableObject()
try
{

}
finally
{
    if(d != null) d.Dispose();
}

поэтому вы более или менее спрашиваете, возможно ли принудительно записать блок try/finally, который вызывает Dispose для объекта.

Ответ 5

Интересно, может ли FXCop применить это правило?

Ответ 6

Нет, вы не можете этого сделать. Вы даже не можете заставить их позвонить в распоряжение. Лучшее, что вы можете сделать, это добавить финализатор. Просто имейте в виду, что финализатор будет вызван, когда объект будет удален, и это зависит от времени выполнения.

Ответ 7

Нет, это невозможно. Теперь то, что вы можете сделать, это вызвать метод dispose в финализаторе класса (а затем вы можете запретить его использование, если они действительно назовут метод dispose). Таким образом он будет срабатывать, если не сделать явно в коде.

Эта ссылка покажет вам, как реализовать шаблон finalizer/dispose:

http://www.devx.com/dotnet/Article/33167

Ответ 8

Если вы хотите использовать силу в этом классе, ваш код для поддержки этого класса, который вы можете использовать в другом классе, и скрыть MyClass для нормального использования.

Ответ 9

Вы должны изучить RAII, который является методом, который гарантирует, что приобретенные ресурсы будут правильно размещены.

Я имею в виду, что если вы не можете заставить метод Dispose вызываться (через using или напрямую), вы можете поместить его содержимое в другой метод, который будет вызываться, например деструктор.

Это обычная модель для реализации IDisposable, как показано ниже:

// 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.
private 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.

        // TODO: write code
    }
    disposed = true;         
}

// 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.
~ClassName()
{
    // Do not re-create Dispose clean-up code here.
    // Calling Dispose(false) is optimal in terms of
    // readability and maintainability.
    Dispose(false);
}

Источник: http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx

Ответ 10

Если вы хотите принудительно удалить ресурсы с областью действия, это возможно, но IDisposable действительно не требуется. Со следующим кодом:

public class ResourceHandle
{
    public delegate void ResourceProvider(Resource resource);

    private string _parms;

    public ResourceHandle(string parms)
    {
        _parms = parms;
    }

    public void UseResource(ResourceProvider useResource)
    {
        Resource resource = new Resource(_parms);
        useResource(resource);
        resource.Close();
    }
}


public class Resource
{
    private string _parms;

    internal Resource(string parms)
    {
        // Initialize resource
    }

    internal void Close()
    {
        // Do cleaning
    }

    // Public methods of resource
}

Вы можете использовать ресурс ТОЛЬКО таким образом:

public void foo()
{
    ResourceHandle resourceHandle = new ResourceHandle("parms");

    resourceHandle.UseResource(delegate(Resource resource)
        {
            // use resource
        });
}

Как вы можете видеть, IDisposable здесь не нужен.