Tip: использование ReSharper совместно с Microsoft CodeContracts

7 Окт
2011

Решил написать небольшую заметку после пары часов разбирательств — в сети ответы находятся не сразу, кусочками и на английском.
Про Microsoft CodeContracts на Блоге уже писали, это библиотека и инструментарий для Visual Studio, позволяющие использовать в C# элементы «контрактного программирования».
Мы начали использовать CodeContracts (далее — просто «контракты») в своих проектах относительно недавно, и, в целом, довольны, хоть и получили дополнительных несколько секунд ожидания к времени компиляции.
Ну, и, конечно, мы используем ReSharper, который в дополнительном представлении не нуждается.
Но есть пара нюансов, заключающихся в том, что для эффективной работы эти два инструмента нужно немножко подружить между собой.

Нюанс 1. Method invocation is skipped

Первым делом вы заметите, что по-умолчанию ReSharper думает, что некоторые вызовы контрактов типа нижеследующих будут исключены из сборки, и нещадно «засеривает» их:
ReSharper думает, что компилятор исключит контрактную проверку
На самом деле эти вызовы не исключаются из сборки. Некоторые методы контрактов, типа
Contract.Requires
и
Contract.Ensures
, помечены атрибутом
[Conditional("CONTRACTS_FULL")]
, но при этом флажок
CONTRACTS_FULL
выставляется механизмом контрактов перед компиляцией, уже на этапе сборки проекта, и поэтому не виден на этапе редактирования ReSharper’у, который смотрит на перечень заданных символов компиляции в настройках.
После обычной компиляции механизмы контрактов инструментируют получившийся IL-код, и заменяют эти вызовы на другие, из класса
__ConstractRuntime
. Подробнее это можно легко посмотреть Reflector’ом (торопитесь, пока он еще бесплатный).
А вот вызовы
Contract.Assert
присутствуют в коде с самого начала, и они же работают во время выполнения, без переписывания. Они помечены не только как
[Conditional("CONTRACTS_FULL")]
, но еще и как
Conditional("DEBUG")
. В результате — для отладочной конфигурации (где определен символ
DEBUG
) ReSharper и сам понимает, что этот вызов — настоящий.
Так как же объяснить ReSharper’у, что
Contract.Requires
— тоже «честный» вызов, и его не следует «засеривать» в редакторе? Нужно просто для той конфигурации проекта, в которой у вас включены проверки контрактов времени выполнения (опции проекта «Code Contracts» > «Runtime Checking») выставить также вручную символ условной компиляции
CONSTRACTS_FULL
на вкладке «Build».
ReSharper тут же «увидит» недостающие методы! Конечно, не слишком удобно повторять значение флажков, уже выставленных на одной вкладке, еще и на другой вкладке, но, по крайней мере, это можно сделать один раз на конфигурацию проекта.
В JetBrains уже знают об этой проблемке, и, можно надеяться, в следующих версиях контракты будут поддержаны ReSharper’ом «из коробки».
Нюанс 2. Possible NullReferenceException

Еще одна настройка, которую необходимо сделать для максимального использования возможностей ReSharper с контрактами — это настройка анализа значений (value analysis). В частности, ReSharper умеет выявлять наличие/отсутствие проверок параметров метода на
null
и, соответственно, предупреждает о возможном выбросе исключения
NullReferenceException
при обращении к методам объекта-аргумента при отсутствии такой проверки:
ReSharper не понимает, что контракты проверяют аргумент на null
При этом по-умолчанию ReSharper не может догадаться, что добавление контрактного предусловия
Contract.Requires(visitor != null)
обеспечивает необходимую проверку на
null
.
К счастью, в ReSharper предусмотрен механизм т.н. External annotations, который позволяет разметить классы и методы из сторонних библиотек дополнительной метаинформацией для ReSharper’а. Конкретно, чтобы ReSharper начал «узнавать» проверки контрактов, нужно ему в папку «\Bin\ExternalAnnotations\mscorlib\» добавить специальный xml-файлик с метаописанием методов класса
Contract
:

    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    
    
        
        
            
                0
            
        
    



После этого все становится на свои места, и вы снова с удовольствием можете довериться подсказкам любимого инструмента, не держа в голове случаи, когда он заблуждается из-за применения CodeContracts!
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх