Что лучше использовать и почему в большом проекте:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
или
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Что лучше использовать и почему в большом проекте:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
или
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Ответы:
Это действительно зависит от того, что вы собираетесь:
#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
}
против:
[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. Во втором примере const 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 debug
или подобная конструкция в вашем коде?
#if DEBUG
чтобы мы не случайно спамили других во время тестирования системы, которая должна передавать электронную почту как часть процесса. Иногда это правильные инструменты для работы :)
Этот также может быть полезен:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttached
должен вызываться во время выполнения даже в сборках выпуска.
В первом примере, SetPrivateValue
не будет существовать в сборке , если DEBUG
не определено, то со вторым , например, требует , чтобы SetPrivateValue
не будет существовать в сборке , если DEBUG
не определено.
В первом примере, вам придется обернуть любые звонки SetPrivateValue
с #if DEBUG
а.
Во втором примере вызовы SetPrivateValue
будут опущены, но имейте в виду , что SetPrivateValue
сам по себе все равно будет скомпилирован. Это полезно, если вы создаете библиотеку, поэтому приложение, ссылающееся на вашу библиотеку, все еще может использовать вашу функцию (если выполняется условие).
Если вы хотите пропустить вызовы и сэкономить место вызываемого абонента, вы можете использовать комбинацию из двух методов:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
#if DEBUG
вокруг Conditional("DEBUG")
не удаляют вызовы этой функции, она только удаляет функцию из IL ALLtogether, так что вы все еще есть вызов функции , которая не существует (ошибки компиляции).
Давайте предположим, что в вашем коде также есть #else
оператор, который определил нулевую функцию-заглушку, адресованную одному из пунктов Джона Скита. Есть второе важное различие между ними.
Предположим, что функция #if DEBUG
или Conditional
существует в DLL, на которую ссылается исполняемый файл вашего основного проекта. Используя #if
, оценка условного выражения будет выполняться с учетом параметров компиляции библиотеки. Используя Conditional
атрибут, оценка условия будет выполняться с учетом параметров компиляции вызывающего.
У меня есть расширение SOAP WebService для регистрации сетевого трафика с использованием пользовательских [TraceExtension]
. Я использую это только для отладочных сборок и опускаю из сборок выпуска . Используйте атрибут, #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(...)
Обычно вам это нужно в Program.cs, где вы решаете запустить Debug для кода без отладки, и это тоже в основном в Windows Services. Поэтому я создал поле IsDebugMode только для чтения и установил его значение в статическом конструкторе, как показано ниже.
static class Program
{
#region Private variable
static readonly bool IsDebugMode = false;
#endregion Private variable
#region Constrcutors
static Program()
{
#if DEBUG
IsDebugMode = true;
#endif
}
#endregion
#region Main
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
if (IsDebugMode)
{
MyService myService = new MyService(args);
myService.OnDebug();
}
else
{
ServiceBase[] services = new ServiceBase[] { new MyService (args) };
services.Run(args);
}
}
#endregion Main
}