2010-04-22 3 views
10

Я получаю предупреждение при запуске некоторого кода с помощью утилиты Code Analysis Visual Studio, которую я не уверен, как ее решить. Возможно, кто-то здесь столкнулся с подобной проблемой, разрешил ее и готов поделиться своим пониманием.CA2000 Передача ссылки объекта на базовый конструктор в C#

Я программирую специально окрашенную ячейку, используемую в элементе управления DataGridView. Код напоминает:

public class DataGridViewMyCustomColumn : DataGridViewColumn 
{ 
    public DataGridViewMyCustomColumn() : base(new DataGridViewMyCustomCell()) 
    { 
    } 

Он генерирует следующее предупреждение:

CA2000: Microsoft.Reliability: В методе 'DataGridViewMyCustomColumn.DataGridViewMyCustomColumn()' называют System.IDisposable.Dispose на объекте «новый DataGridViewMyCustomCell() 'прежде чем все ссылки на него выходят за рамки.

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

Примеры, которые я видел в Интернете, предлагают использовать блок для охвата времени жизни объекта и система автоматически удаляет его, но база не распознается при перемещении в тело конструктора, поэтому я могу " t напишите вокруг него блок использования ..., который я не уверен, что мне все равно придется делать это, так как это не даст указание запустить время, чтобы освободить объект, который еще может быть использован позже в базовом классе?

Мой вопрос тогда, это код в порядке, как есть? Или, как он может быть реорганизован для разрешения предупреждения? Я не хочу подавлять предупреждение, если это действительно не подходит для этого.

ответ

18

Если вы используете Visual Studio 2010, то CA2000 полностью сломается. Он также может быть поврежден в других версиях FxCop (анализ кода a.k.a.), но VS2010 является единственным, за который я могу ручаться. Наш кодовый дают предупреждение CA2000 для кода, как это ...

internal static class ConnectionManager 
{ 
    public static SqlConnection CreateConnection() 
    { 
     return new SqlConnection("our connection string"); 
    } 
} 

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

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

+3

+1 для «полностью разбитого в VS10». Мне очень сложно убедить людей присоединиться ко мне на улучшении качества кода, когда инструменты заставляют меня выглядеть таким глупым ... –

0

Спасибо, Грег. Это мое беспокойство - некоторые положительные моменты, которые должны быть исправлены .. Ну, возможно, на следующей итерации VS это будет более точно. Сейчас я буду подавлять предупреждение в коде.

+0

Я включил в свой код следующее подавление: '[System.Diagnostics.CodeAnalysis.SuppressMessage (« Microsoft .Relability "," CA2000: Dispose объектов перед потерей области. Это нарушенное правило. См. Http://stackoverflow.com/q/2687398/228059 для более ")]' – noonand

+0

Или вы можете создать файл .ruleset, выбрать которые вы хотите сохранить и связать с ними для создания типов в свойствах решения. Вот [пример] (https://github.com/madskristensen/WebEssentials2013/blob/master/EditorExtensions/CodeAnalysis.ruleset). По умолчанию VS откроет редактор режима проекта с флажками для файла .ruleset. –

1

Нет надежного и элегантного способа, чтобы связанный конструктор передавал новый объект IDisposable базовому конструктору, поскольку, как вы заметили, невозможно связать цепочный вызов конструктора в любом виде try finally.Существует подход, который является безопасным, но это вряд ли элегантна: определить полезность метод что-то вроде:

internal static TV storeAndReturn<TR,TV>(ref TR dest, TV value) where TV:TR 
{ 
    dest = value; return value; 
} 

Иметь конструктор смотреть что-то вроде:

protected DataGridViewMyCustomColumn(ref IDisposable cleaner) : 
    base(storeAndReturn(ref cleaner, new DataGridViewMyCustomCell())) 
{ 
} 

кодекса, который нуждается в новый объект будет тогда иметь для вызова общедоступного статического заводского метода, который бы назвал соответствующий конструктор в блоке , чья основная строка отклоняла бы cleaner незадолго до его завершения и чей блок finally вызывал бы Dispose по адресу cleaner, если он не является нулевым , При условии, что каждый подкласс определяет аналогичный заводский метод, этот подход гарантирует, что новый объект IDisposable будет удален, даже если возникает исключение между созданным временем и временем, в течение которого инкапсулирующий объект подвергается клиенту. Образец уродливый, но я не уверен, что какой-либо более хороший другой образец обеспечит правильность.

 Смежные вопросы

  • Нет связанных вопросов^_^