Ответ 1
Начиная с версии 4.5.2 структуры (возможно, даже 4.5), можно рассказать Code Analysis о заключении контрактов, заключенных в Code Contracts. Сначала создайте следующий метод расширения и атрибут маркера
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
/// <summary>Extension methods to enhance Code Contracts and integration with Code Analysis.</summary>
public static class ContractExtensions {
#if RUNTIME_NULL_CHECKS
/// <summary>Throws <c>ArgumentNullException{name}</c> if <c>value</c> is null.</summary>
/// <param name="value">Value to be tested.</param>
/// <param name="name">Name of the parameter being tested, for use in the exception thrown.</param>
[ContractArgumentValidator] // Requires Assemble Mode = Custom Parameter Validation
public static void ContractedNotNull<T>([ValidatedNotNull]this T value, string name) where T : class {
if (value == null) throw new ArgumentNullException(name);
Contract.EndContractBlock();
}
#else
/// <summary>Throws <c>ContractException{name}</c> if <c>value</c> is null.</summary>
/// <param name="value">Value to be tested.</param>
/// <param name="name">Name of the parameter being tested, for use in the exception thrown.</param>
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value")]
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "name")]
[ContractAbbreviator] // Requires Assemble Mode = Standard Contract Requires
public static void ContractedNotNull<T>([ValidatedNotNull]this T value, string name) where T : class {
Contract.Requires(value != null,name);
}
#endif
}
/// <summary>Decorator for an incoming parameter that is contractually enforced as NotNull.</summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public sealed class ValidatedNotNullAttribute : global::System.Attribute {}
и теперь конвертируйте ваши нулевые тесты в следующий формат:
/// <summary>IForEachable2{TItem} implementation</summary>
public void ForEach(FastIteratorFunctor<TItem> functor) {
functor.ContractedNotNull("functor"); // for Code Analysis
TItem[] array = _array;
for (int i = 0; i < array.Length; i++) functor.Invoke(array[i]);
}
Имя метода ContractedNotNull и переключатель компиляции RUNTIME_NULL_CHECKS можно, конечно, изменить на все, что соответствует вашему стилю именования.
Вот оригинальный блог, который сообщил мне об этой технике, которую я немного уточнил; большое спасибо Терье Сандстрому за публикацию своих исследований.
Rico Suter расширяет эту здесь, используя дополнительные атрибуты, чтобы отладчик и inliner были более умными: