CA2000 при возврате одноразового объекта из метода
У меня есть метод factory, который строит объекты, которые реализуют IDisposable
. В конечном счете это вызывающие, которые управляют временем жизни созданных объектов. Эта конструкция запускает кучу ошибок CA2000. Есть ли что-то принципиально неправильное в моем дизайне, нужно ли ему рефакторинг, или это просто слишком возбуждает предупреждения о статическом анализе кода?
Метод factory
public static DisposableType BuildTheDisposableType(string param1, int param2)
{
var theDisposable = new DisposableType();
// Do some work to setup theDisposable
return theDisposable
}
Вызывающий
using(var dt = FactoryClass.BuildTheDisposableType("data", 4))
{
// use dt
}
Ответы
Ответ 1
Я бы рекомендовал вам подавить предупреждение CA2000 для каждого индивидуального метода factory или, возможно, для всего класса, который их содержит (но только если это единственная функция этого класса).
Далее я рекомендую включить обоснование:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability",
"CA2000:Dispose objects before losing scope",
Justification = "This is a factory method. Caller must dispose")]
Ответ 2
Вы должны сохранить его в локальной переменной и перенести инициализацию в блок try-catch-rethrow, распорядиться в случае любого исключения:
public MyDisposable CreateDisposable()
{
var myDisposable = new MyDisposable();
try
{
// Additional initialization here which may throw exceptions.
ThrowException();
}
catch
{
// If an exception occurred, then this is the last chance to
// dispose before the object goes out of scope.
myDisposable.Dispose();
throw;
}
return myDisposable;
}
Старайтесь никогда не оставлять одноразовый объект уязвимым для исключений, когда Dispose
не будет называться
PS: кто-то ранее упомянул, чтобы убрать внутри окончательно - это, очевидно, неправильно - в пути без исключения вы не хотите вызывать Dispose
Ответ 3
Вы получаете ошибку, потому что создатель одноразового объекта не управляет им. Однако в дизайне нет ничего принципиально неправильного. Вы просто полагаетесь на потребителей, чтобы использовать using
. Не так сильно отличается от существующих объектов ADO, например.
Ответ 4
Другой альтернативой является изменение метода factory на метод "конфигурации" и ответственность за создание одноразового объекта на клиенте. Пример:
public void SetupDisosableThing(IDisposable foo)
{
foo.Bar = "baz";
}
void Main()
{
using (var x = new Thing())
{
SetupDisposableThing(x);
}
}