#if DEBUG против условного (“DEBUG”)
Что лучше использовать и почему, по большому проекту:
#if DEBUG public void SetPrivateValue(int value) { ... } #endif
или
[System.Diagnostics.Conditional("DEBUG")] public void SetPrivateValue(int value) { ... }
- «В настоящий момент точка останова не будет удалена. Исходный код отличается от исходного. «Что это значит?
- Как вы отлаживаете хранимые процедуры MySQL?
- Отслеживать все вызовы метода ObjC?
- Как отлаживать скрипт перезаписи htaccess
- Что такое личные байты, виртуальные байты, рабочий набор?
- Где читать консольные сообщения из background.js в расширении Chrome?
- Ошибка: не удается получить доступ к файловому ящику / Debug / ..., потому что он используется другим процессом
- Как получить аварийную свалку
- Запуск приложения в GDB до тех пор, пока не произойдет исключение
- Как сгенерировать символ отладки gcc вне цели сборки?
- Прикрепить отладчик к экземпляру IIS
- Существуют ли какие-либо средства перехвата HTTP / HTTPS, такие как Fiddler для Mac OS X?
- iphone - NSTimers в фоновом режиме
Это действительно зависит от того, что вы собираетесь делать:
-
#if DEBUG
: Код здесь даже не дойдет до релиза IL. -
[Conditional("DEBUG")]
: этот код достигнет ИЛ, однако вызовы метода будут опущены, если 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 }
против:
[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
В первом примере код все существует, но просто игнорируется, если не включен DEBUG. Во втором примере константа ENDPOINT установлена в «Localhost» или «BasicHttpBinding» в зависимости от того, установлен ли DEBUG или нет.
Обновление: я обновляю этот ответ, чтобы прояснить важный и сложный вопрос. Если вы решите использовать ConditionalAttribute
, имейте в виду, что во время компиляции не выполняются вызовы, а не время выполнения . То есть:
MyLibrary.dll
[Conditional("DEBUG")] public void A() { Console.WriteLine("A"); B(); } [Conditional("DEBUG")] public void B() { Console.WriteLine("B"); }
Когда библиотека скомпилирована в режиме деблокирования (т. Е. Не имеет символа DEBUG), навсегда будет вызываться вызов B()
из A()
, даже если включен вызов A()
поскольку DEBUG определен в вызывающей сборке ,
Ну, стоит отметить, что они не означают одно и то же.
Если символ DEBUG не определен, то в первом случае сам SetPrivateValue
не будет вызываться … тогда как во втором случае он будет существовать, но любые вызывающие , которые скомпилированы без символа DEBUG, будут иметь эти пропущенные вызовы.
Если код и все его вызывающие лица находятся в одной и той же сборке, это различие менее важно, но это означает, что в первом случае вам также необходимо иметь #if DEBUG
вокруг кода вызова .
Лично я бы порекомендовал второй подход, но вам нужно сохранить разницу между ними в своей голове.
Я уверен, что многие со мной не согласятся, но, проведя время, когда парень по сборке постоянно слышит: «Но это работает на моей машине!», Я придерживаюсь мнения, что вы почти никогда не будете использовать его. Если вам действительно нужно что-то для тестирования и отладки, выясните способ сделать эту тестируемость отдельно от фактического производственного кода.
Проанализируйте сценарии, издеваясь над модульными тестами, сделайте одну из версий для одного сценария, который вы хотите протестировать, но не ставьте тесты для отладки в код для двоичных файлов, которые вы тестируете и записываете для выпуска продукции. Эти тесты отладки просто скрывают возможные ошибки от разработчиков, поэтому они не будут найдены дольше в этом процессе.
Это также может быть полезно:
if (Debugger.IsAttached) { ... }
В первом примере SetPrivateValue
не будет существовать в сборке, если DEBUG
не определен, а во втором примере вызовы SetPrivateValue
не будут существовать в сборке, если DEBUG
не определен.
В первом примере вам нужно будет обернуть любые вызовы SetPrivateValue
с помощью #if DEBUG
.
Во втором примере вызовы SetPrivateValue
будут опущены, но имейте в SetPrivateValue
что SetPrivateValue
сам по-прежнему будет скомпилирован. Это полезно, если вы создаете библиотеку, поэтому приложение, ссылающееся на вашу библиотеку, все равно может использовать вашу функцию (если условие выполнено).
Если вы хотите опустить вызовы и сохранить пространство вызываемого абонента, вы можете использовать комбинацию двух методов:
[System.Diagnostics.Conditional("DEBUG")] public void SetPrivateValue(int value){ #if DEBUG // method body here #endif }
Предположим, что у вашего кода также был оператор #else
который определял нулевую функцию заглушки, обращаясь к одной из точек Джона Скита. Второе важное различие между ними.
Предположим, что функция #if DEBUG
или Conditional
существует в DLL, на которую ссылается ваш основной исполняемый файл проекта. Используя #if
, оценка условного будет выполняться в отношении настроек компиляции библиотеки. Используя условный атрибут, оценка условного будет выполняться в отношении настроек компиляции invoker.
У меня есть расширение SOAP WebService для регистрации сетевого трафика с помощью пользовательского [TraceExtension]. Я использую это только для сборки Debug и опускаю из сборки Release. Используйте #if DEBUG, чтобы обернуть атрибут [TraceExtension], тем самым удалив его из сборки Release.
#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(...)