Ответ 1
Невозможно обеспечить его выполнение, но вы можете создать правило пользовательского анализа кода, чтобы отметить его.
Я заметил некоторые потенциально опасные классы, которые были бы намного менее опасными, если бы они не могли быть созданы, если только они не были сделаны в рамках используемого оператора.
Мне интересно, есть ли способ заставить классы только создаваться таким образом.
(Я знаю, что собирает IL, потому что я не уверен, что это даже возможно)
Приветствия,
Фил.
Невозможно обеспечить его выполнение, но вы можете создать правило пользовательского анализа кода, чтобы отметить его.
Нет, нет способа заставить компилятор обеспечить это. Было бы опасно сделать это, в любом случае, так как есть моменты, когда вы хотите использовать классы IDisposable
в других моделях, например, инкапсулировать их во втором impelementation IDisposable
и т.д.
Если ваш класс правильно реализован, деструктор должен очистить любые неуправляемые, нераспределенные ресурсы. Это меньше, чем идеально, но все же может работать.
Одним из хороших вариантов является то, что деструктор создает исключение или журнал во время отладки. Это может помочь вам отслеживать во время тестирования и времени отладки любые "пропущенные" случаи использования IDisposable
ненадлежащим образом.
Для всех эффективных целей это невозможно. Тем более, что это не должно быть using
, кто-то мог бы записать try{}finally{}
. Вы можете убедиться, что все неуправляемые были правильно утилизированы в финализаторе.
Это сделает ваш объект доступным только в локальной области. Это означает, что вы не можете безопасно хранить его в поле класса, например.
Хотя вы не можете заставить клиента написать инструкцию using
, вы можете инкапсулировать ресурс в метод, который использует инструкцию using
. Это будет ваш код ресурса:
public sealed class Resource : IDisposable {
private Resource() { }
public void Dispose() { ... }
public void Use(Action<Resource> action) {
using (var resource = new Resource()) {
action(resource);
}
}
}
Теперь код клиента вынужден использовать Resource
через его метод Use
:
Resource.Use(resource => {
// use the resource...
});
Нет, такого способа нет, так как оператор using
является синтаксическим сахаром.
Вы действительно этого не хотите, хотя это кажется хорошей идеей. Это означает, что ваши экземпляры могут иметь только локальную область и что вы не можете передавать одноразовые объекты другим методам или использовать их в качестве переменных поля в своем классе.
Что вам нужно сделать, это реализовать удалить шаблон в своем классе, чтобы они были правильно очищены.
Трюк, который я видел, использовал (и действительно использовал сам), - это отметить стек вызовов во время построения объекта, а затем создать Debug.Assert в деструкторе, который уведомляет разработчика стека вызовов, когда объект был создан. Это очень помогло в отслеживании того, откуда появился неподходящий объект, и поэтому помог найти место, где объект, ответственный за удаление, не делал этого. Что-то в этих строках (у меня нет доступа к коду, который я использовал, поэтому это моя лучшая предпосылка, YMMV):
private StackTrace m_stackAtConstruction;
private bool m_disposed;
public Constructor()
{
m_stackAtConstruction = new StackTrace();
m_disposed=false;
}
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 you need thread safety, use a lock around these
// operations, as well as in your methods that use the resource.
if (!m_disposed)
{
if (disposing) {
if (_resource != null)
_resource.Dispose();
}
else
{
Console.WriteLine("Object not disposed correctly - Stack trace at construction was " + m_stackAtConstruction.ToString());
}
// Indicate that the instance has been disposed.
_resource = null;
_disposed = true;
}
}
CA2000, CA2202 и CA2213 охватывает это посредством статического анализа кода. Просто настройте эти правила, чтобы привести к ошибкам, и вы получите сбой времени компиляции. Почему даже ждать времени выполнения для исключения?
Нет, не совсем - это будет действительно навязчиво для разработчиков. Я думаю, что вы ищете инструмент статического анализа, такой как FxCop, чтобы обеспечить правильное размещение одноразовых объектов.