2008-12-27 1 views
1

Я пишу (очень маленькую) структуру для проверки пред- и постусловий методов. точки входа (они могут быть легко быть методами, это не имеет значения):Возможно ли в .Net вызывать некоторый код только из отладочных сборников клиентских сборок?

public static class Ensures { 
    public static Validation That { 
     get { ... } 
    } 
} 

public static class Requires { 
    public static Validation That { 
     get { ... } 
    } 
} 

Очевидно, что проверка постусловий может быть дорогим, и фактически не является необходимым, когда метод не глючит. Поэтому я хочу метод, который работает следующим образом:

public static class Ensures { 
    [ConditionalCallingCode("DEBUG")] 
    public static Validation ThatDuringDebug { 
     get { ... } 
    } 
} 

где ConditionalCallingCodeAttribute означает, что этот метод должен работать только тогда, когда вызывающий код скомпилирован с символом DEBUG определен. Это возможно?

Я хочу, чтобы код клиента выглядеть следующим образом:

public class Foo { 
    public void Bar() { 
     ... // do some work 
     Ensures.That // do these checks always 
      .IsNotNull(result) 
      .IsInRange(result, 0, 100); 

     Ensures.WhileDebuggingThat // only do these checks in debug mode 
      .IsPositive(ExpensiveCalculation(result)); 

     return result; 
    } 
} 

Конечно, я могу просто не обеспечить WhileDebuggingThat. Затем клиентский код будет выглядеть следующим образом:

public class Foo { 
    public void Bar() { 
     ... // do some work 
     Ensures.That // do these checks always 
      .IsNotNull(result) 
      .IsInRange(result, 0, 100); 

     #ifdef DEBUG 
     Ensures.That // only do these checks in debug mode 
      .IsPositive(ExpensiveCalculation(result)); 
     #endif 

     return result; 
    } 
} 

Это план запасного варианта, если ничего не работает, но он ломает DRY очень плохо.

Как я понимаю, маркировка WhileDebuggingThat с [Conditional("DEBUG")] будет излучать (или нет) этот метод в зависимости от того DEBUG определяется во время компиляции библиотеки, не из сборок, которые ссылаются на эту библиотеку. Итак, я мог бы сделать это, а затем написать документацию, сообщающую пользователям библиотеки связывать сборки отладки их кода с отладочной сборкой библиотеки и выпускать сборки с релизными сборками. Это не кажется мне лучшим решением.

Наконец, я мог бы сказать пользователям библиотеки, чтобы определить этот класс в своих проектах:

using ValidationLibrary; 
public static class EnsuresWhileDebugging { 
    [Conditional("DEBUG")] 
    public static Validation That() { 
     return Ensures.That; 
    } 
} 

Это должно работать так же, насколько я вижу, но по-прежнему требует нарушения DRY принцип, если только слегка ,

+0

Разве это не утверждение? –

+0

Утверждения работают для проверки постусловий (и только в отладочных сборках, я хочу также разрешить оставлять проверки условий в сборках релизов), не проверяя предварительные условия. –

ответ

1

Любое решение, которое нашли здесь будет медленнее, чем фактическая чеки. Кроме того, поскольку он не будет встроен в компилятор, такой как ConditionalAttribute, параметры все равно будут вычислены. Если постусловия могут быть очень сложными, например,

Ensures.That.IsPositive(ExpensiveCalculation(result)); 

Вы могли бы рассмотреть вопрос об использовании предложения icelava, чтобы отразить на сборке вызывающей найти, если он будет построен в отладках или отпустить - но тогда вы должны использовать какое-то делегат отложить расчет - чтобы убедиться, что он выполняется только в случае необходимости. например .:

Ensures.WhileDebugging.That. IsPositive(() => ExpensiveCalculation(result)); 

IsPositive функция должна работать лямбда и проверить свой результат, только после отражения, чтобы выяснить, если она должна быть рассчитана.

+0

Да, но я считаю, что это неприемлемые накладные расходы для этого конкретного приложения. –

+0

Какая часть накладных расходов? – configurator

3

Это что-то, что нормальный ConditionalAttribute не делает для вас, помимо работы над собственностью вместо метода? Вам может потребоваться изменить способ, которым вещи называются так, что у вас есть методы вместо свойств, и тот факт, что он возвращает значение, может вызвать проблемы.

Это очень поможет, если вы покажете, как используется ваша фреймворк - в настоящее время нам не с кем работать.

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

0

Похоже, что большинство из того, что вы делаете, уже покрыто с помощью Debug.Assert().

В этом отношении, этот код будет только когда-либо работать в режиме отладки (но вы должны мириться с уловах блока медлительности):

try 
{ 
    Debug.Assert(false); 
} 
catch (Exception e) 
{ 
    // will only and always run in debug mode 

} 
+0

Debug.Assert() работает только для постусловий. Если я хочу иметь один и тот же API для проверки предварительных и постусловий или просто переключаться между условиями отладки и всегда проверяемыми постулатами, это не подходит. –

0

Похоже, что я хочу просто не доступен. Вероятно, я соглашусь предоставить неявное преобразование от Validation до bool, так что проверка проверки может быть завернута в Debug.Assert().

0

Метод Debug Assert можно установить/изменить с помощью логического значения, даже после того, как программа скомпилирована, если, например, значение берется из пользовательского проекта SETING:

Debug.Assert(!Properties.Settings.Default.UseAutoDebug); 
0

Я не уверен, но я подумайте, что вы можете использовать ConditionalAttribute для этого: испускать вызов или не испускать будет зависеть от типа сборки пользователя, а не от вашей библиотеки. Вы можете проверить это с помощью Reflector или ILDasm: скомпилируйте ваши образцы и в Reflector (ILDasm) посмотрите, вызывается ли звонок или нет в проекте образца.

0

У меня это происходит: Project Вызов 1 функция B. B включить эту функцию:. Assembly.GetCallingAssembly() ПолноеИмя Если сборка B в режиме отладки, то работает, эта функция возвращает имя проекта A, if build при выпуске режима, чем имя возврата проекта B. Я не знаю, почему это происходит. Пожалуйста, поддержите меня Спасибо

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