Можно ли в .Net вызывать некоторый код только из отладочных сборок клиентских сборок? - PullRequest
1 голос
/ 27 декабря 2008

Я пишу (очень маленький) фреймворк для проверки предварительных и постусловий методов. Точки входа (они могут быть легко методами; это не имеет значения):

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;
    }
}

Конечно, я просто не могу предоставить пока отладку, что. Тогда код клиента будет выглядеть так:

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;
    }
}

Это запасной план, если больше ничего не получается, но он действительно сильно нарушает СУХОЙ.

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

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

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

Насколько я понимаю, это также должно работать, но все же требует нарушения принципа СУХОЙ, хотя бы немного.

Ответы [ 8 ]

3 голосов
/ 27 декабря 2008

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

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

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

1 голос
/ 28 декабря 2008

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

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

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

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

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

0 голосов
/ 16 июня 2009

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

0 голосов
/ 30 декабря 2008

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

0 голосов
/ 30 декабря 2008

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

Debug.Assert(!Properties.Settings.Default.UseAutoDebug);
0 голосов
/ 29 декабря 2008

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

0 голосов
/ 27 декабря 2008

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

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

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

}
0 голосов
/ 27 декабря 2008

Я не пробовал этого, так как собираюсь вымыться и уйти из дома.

  1. Вызовите Assembly.GetCallingAssembly (), чтобы получить сборку, из которой происходит метод (класс), вызывающий ваш текущий исполняемый метод.
  2. Запустите проверку этого объекта Assembly, чтобы увидеть, является ли он Release или Debug build .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...