在大型项目中,哪种方法更好,为什么使用:
#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)
{ ... }
Answers:
这实际上取决于您要做什么:
#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,将const ENDPOINT设置为“ Localhost”或“ BasicHttpBinding”。
更新:我正在更新此答案以阐明重要且棘手的问题。如果选择使用ConditionalAttribute
,请记住,在编译过程中会忽略调用,而在运行时则不会。那是:
MyLibrary.dll
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
当针对发布模式(即,没有DEBUG符号)编译该库时,即使其中包含对的调用,也将永远忽略B()
from内A()
的调用,A()
因为在调用程序集中定义了DEBUG。
好吧,值得注意的是,它们根本不是同一件事。
如果未定义DEBUG符号,则在第一种情况下SetPrivateValue
将不会调用其本身...而在第二种情况下,它将本身存在,但编译时未使用DEBUG符号的任何调用程序都将忽略这些调用。
如果代码及其所有来电号码在同一装配这种差异是不太重要的-但它意味着,在第一种情况下,你还需要有#if DEBUG
各地的调用代码。
就个人而言,我建议使用第二种方法-但您确实需要清楚地了解它们之间的区别。
我敢肯定,很多人会不同意我的观点,但是作为一名构建专家,我经常听到“但是它在我的机器上可以正常工作!”,我认为您几乎不应该使用它们。如果您确实需要测试和调试的东西,请找出一种使可测试性与实际生产代码分离的方法。
在单元测试中通过模拟来抽象场景,为要测试的一个场景创建一个版本的事物,但是不要将要调试的测试放入要为生产发行版测试和编写的二进制代码中。这些调试测试只是隐藏了开发人员可能遇到的错误,因此直到该过程的后期才发现它们。
#if debug
代码中的任何类似构造?
#if DEBUG
这样的方式进行操作,以便在测试必须在过程中传输电子邮件的系统时,不会意外向其他人发送垃圾邮件。有时,这些是完成工作的正确工具:)
与第一示例中,SetPrivateValue
在构建将不存在,如果DEBUG
没有定义,与第二示例中,调用到SetPrivateValue
如果在构建将不存在DEBUG
没有被定义。
在第一个示例中,您还必须包装对SetPrivateValue
with的所有调用#if DEBUG
。
在第二个示例中,SetPrivateValue
将省略对的调用,但要注意,SetPrivateValue
其本身仍将被编译。如果您正在构建库,这将很有用,因此引用您的库的应用程序仍可以使用您的函数(如果满足条件)。
如果要忽略呼叫并节省被呼叫者的空间,可以使用以下两种技术的组合:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
#if DEBUG
环绕Conditional("DEBUG")
并不会删除对该函数的调用,而只是从IL一起删除了该函数,因此您仍在调用不存在的函数(编译错误)。
假设您的代码中还有一条#else
语句定义了一个空存根函数,以解决Jon Skeet的要点之一。两者之间还有第二个重要区别。
假设#if DEBUG
or Conditional
函数存在于主项目可执行文件引用的DLL中。使用#if
,将对库的编译设置进行条件的评估。使用该Conditional
属性,将针对调用程序的编译设置执行条件的评估。
我有一个SOAP WebService扩展,可以使用custom记录网络流量[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(...)
通常,您需要在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
}