#if DEBUG vs. Conditional ("DEBUG")
что лучше использовать, и почему, на большом проекте:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
или
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
7 ответов
это действительно зависит от того, что вы собираетесь на:
-
#if DEBUG
: код здесь даже не достигнет IL при выпуске. -
[Conditional("DEBUG")]
: этот код достигнет IL, однако звонки метод будет опущен, если DEBUG не установлен при компиляции вызывающего объекта.
лично я использую оба в зависимости от ситуации:
условный ("DEBUG") пример: я использую это, чтобы мне не пришлось вернитесь и отредактируйте мой код позже во время выпуска, но во время отладки я хочу быть уверен, что не сделал никаких опечаток. Эта функция проверяет правильность ввода имени свойства при попытке использовать его в моем INotifyPropertyChanged материале.
[Conditional("DEBUG")]
[DebuggerStepThrough]
protected void VerifyPropertyName(String propertyName)
{
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
Debug.Fail(String.Format("Invalid property name. Type: {0}, Name: {1}",
GetType(), propertyName));
}
вы действительно не хотите создавать функцию с помощью #if DEBUG
если вы не готовы обернуть каждый вызов этой функции с тем же #if DEBUG
:
#if DEBUG
public void DoSomething() { }
#endif
public void Foo()
{
#if DEBUG
DoSomething(); //This works, but looks FUGLY
#endif
}
versus:
[Conditional("DEBUG")]
public void DoSomething() { }
public void Foo()
{
DoSomething(); //Code compiles and is cleaner, DoSomething always
//exists, however this is only called during DEBUG.
}
#if DEBUG пример: я использую это при попытке настроить различные привязки для связи WCF.
#if DEBUG
public const String ENDPOINT = "Localhost";
#else
public const String ENDPOINT = "BasicHttpBinding";
#endif
в первом примере код все существует, но просто игнорируется, если отладка не включена. Во втором примере конечная точка const имеет значение "Localhost" или "BasicHttpBinding" в зависимости от того, установлена отладка или нет.
Update: я обновляю этот ответ, чтобы прояснить важный и сложный момент. Если вы решите использовать ConditionalAttribute
имейте в виду, что звонки опущено во время компиляции, и не выполнения. То есть:
папку "MyLibrary".dll файлы
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
когда библиотека компилируется в режиме выпуска (т. е. без символа отладки), она навсегда будет иметь вызов B()
внутри A()
опущено, даже если вызов A()
включено, потому что DEBUG определен в вызывающей сборке.
ну, стоит отметить, что они вовсе не означают одно и то же.
Если символ debug не определен, то в первом случае SetPrivateValue
сам не будет вызываться... тогда как во втором случае он будет существовать, но любой абоненты у тех, кто скомпилирован без символа отладки, эти вызовы будут опущены.
Если код и все его вызывающие объекты находятся в одной сборке, это различие меньше важно - но это означает, что в первом дело тебе и нужно #if DEBUG
вокруг вызов код, а также.
лично я бы рекомендовал второй подход , но вам нужно держать разницу между ними в голове.
Я уверен, что многие не согласятся со мной, но проведя время как парень сборки постоянно слышит "но он работает на моей машине!- Я придерживаюсь той точки зрения, что вы не должны использовать ни то, ни другое. Если вам действительно нужно что-то для тестирования и отладки, найдите способ сделать эту тестируемость отдельной от фактического производственного кода.
абстрактные сценарии с издевательством в модульных тестах, сделайте одну версию вещей для одного сценария, который вы хотите протестировать, но не ставьте тесты для отладки в коде для двоичных файлов, которые вы тестируете и пишете для производственного выпуска. Эти отладочные тесты просто скрывают возможные ошибки от разработчиков, поэтому они не найдены до конца процесса.
С первым примером,SetPrivateValue
не будет существовать в сборке, если DEBUG
не определено, со вторым примером,звонки to SetPrivateValue
не будет существовать в сборке, если DEBUG
не определен.
в первом примере вам придется обернуть любые вызовы в SetPrivateValue
С #if DEBUG
как хорошо.
со вторым примером вызовы SetPrivateValue
будет опущено, но имейте в виду, что SetPrivateValue
сам по-прежнему будет скомпилирован. Это полезно, если вы строите библиотека, поэтому приложение, ссылающееся на вашу библиотеку, все еще может использовать вашу функцию (если условие выполнено).
если вы хотите опустить вызовы и сохранить пространство вызываемого абонента, вы можете использовать комбинацию двух методов:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
давайте предположим, что ваш код также имел #else
оператор, который определил нулевую функцию заглушки, обращаясь к одной из точек Джона Скита. Есть и второе важное различие между ними.
предположим #if DEBUG
или Conditional
функция существует в DLL, на которую ссылается ваш основной исполняемый файл проекта. С помощью #if
, оценка условного будет выполнена в отношении параметров компиляции библиотеки. С помощью оценка условные будут выполняться в отношении настроек компиляции вызывающего.
У меня есть расширение SOAP WebService для регистрации сетевого трафика с помощью пользовательского [TraceExtension]. Я использую это только для отладочных сборок и исключить из выпусков. Используйте #if DEBUG, чтобы обернуть атрибут [TraceExtension], удалив его из сборок выпуска.
#if DEBUG
[TraceExtension]
#endif
[System.Web.Service.Protocols.SoapDocumentMethodAttribute( ... )]
[ more attributes ...]
public DatabaseResponse[] GetDatabaseResponse( ...)
{
object[] results = this.Invoke("GetDatabaseResponse",new object[] {
... parmeters}};
}
#if DEBUG
[TraceExtension]
#endif
public System.IAsyncResult BeginGetDatabaseResponse(...)
#if DEBUG
[TraceExtension]
#endif
public DatabaseResponse[] EndGetDatabaseResponse(...)