在大型项目中使用哪个更好,为什么:
#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才会省略对该方法的调用。个人而言,我根据情况使用两种方法:
Conditional("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打开时才会被忽略。在第二个示例中,根据DEBUG是否设置,常量ENDPOINT将设置为"Localhost"或"BasicHttpBinding"。
ConditionalAttribute
,请记住,在编译期间调用会被省略,而不是运行时。也就是说:
MyLibrary.dll
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
当库被编译为发布模式时(即没有DEBUG符号),即使调用程序集中定义了DEBUG,从A()
内部调用B()
的语句也将被省略。
值得注意的是,它们并不完全相同。
如果没有定义DEBUG符号,则在第一种情况下,SetPrivateValue
本身将不会被调用...... 而在第二种情况下,它将存在,但所有已编译未使用DEBUG符号的调用者都将被省略。
如果代码及其所有调用者都在同一个程序集中,则这种差异就不那么重要了 - 但这意味着在第一种情况下,您还需要在调用代码周围加上#if DEBUG
。
个人建议采用第二种方法 - 但需要清楚地区分它们之间的区别。
我相信很多人会不同意我的观点,但是作为一个构建工程师,经常听到“在我的机器上可以用!”的说法,我认为你几乎永远不应该使用它们。如果你真的需要一些用于测试和调试的东西,那么请想办法将其与实际的生产代码分开来进行测试。
通过单元测试中的模拟来抽象各种情况,针对你想要测试的特定场景制作一次性版本,但不要将调试测试放入二进制代码的测试和生产发布中。这些调试测试只会隐藏潜在的程序错误,直到后续流程中才会被发现。
#if debug
或任何类似的结构呢? - Richard Ev#if DEBUG
将默认收件人电子邮件设置为自己,这样在测试必须传输电子邮件的系统时就不会意外地向其他人发送垃圾邮件。有时这些工具是完成任务的正确选择 :) - iCollect.it Ltd这个也可能很有用:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttached
。 - Jai对于第一个例子,如果未定义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
语句,它定义了一个空的存根函数,解决了Jon Skeet提出的一个问题。这两者之间还有一个重要的区别。#if DEBUG
或Conditional
函数存在于由主项目可执行文件引用的DLL中。使用#if
,条件的评估将根据库的编译设置执行。使用Conditional
属性,条件的评估将根据调用者的编译设置执行。我有一个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(...)
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
}