#if DEBUG vs. Conditional (“DEBUG”) 사용하는 것이 더 나은 이유는 무엇입니까? #if DEBUG

큰 프로젝트에서 사용하는 것이 더 나은 이유는 무엇입니까?

#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가 설정되어 있지 않으면 무시됩니다. 두 번째 예에서 const ENDPOINT는 DEBUG 설정 여부에 따라 “Localhost”또는 “BasicHttpBinding”으로 설정됩니다.


업데이트 : 중요하고 까다로운 요점을 명확히하기 위해이 답변을 업데이트하고 있습니다. 를 사용하기로 선택한 경우 에는 런타임이 아니라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자체 호출되지 않지만 두 번째 경우에는 존재하지만 DEBUG 기호없이 컴파일 된 호출자 는 해당 호출을 생략합니다.

코드와 모든 호출자가 동일한 어셈블리에있는 경우이 차이는 중요합니다. 그러나 첫 번째 경우 에도 호출 코드 #if DEBUG주위 에 있어야 합니다.

개인적으로 두 번째 방법을 권장하지만 머리의 차이점을 명확하게 유지해야합니다.


답변

나는 많은 의견에 동의하지 않을 것이라 확신하지만, 빌드 녀석으로서 “하지만 내 컴퓨터에서 작동합니다!” 테스트 및 디버깅에 실제로 필요한 것이 있으면 테스트 가능성을 실제 프로덕션 코드와 분리하는 방법을 찾으십시오.

단위 테스트에서 조롱하여 시나리오를 추상화하고 테스트하려는 하나의 오프 시나리오에 대해 일회성 버전을 작성하지만 프로덕션 릴리스를 위해 테스트하고 작성한 바이너리의 코드에는 디버그 테스트를 넣지 마십시오. 이 디버그 테스트는 개발자로부터 가능한 버그를 숨기므로 나중에 프로세스에서 찾을 수 없습니다.


답변

이것도 유용 할 수 있습니다 :

if (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
}

답변

코드 #else에 Jon Skeet의 요점 중 하나를 다루는 null 스텁 함수를 정의한 명령문이 있다고 가정합시다 . 두 가지 중요한 차이점이 있습니다.

기본 프로젝트 실행 파일에서 참조하는 DLL에 #if DEBUGor Conditional함수가 있다고 가정합니다 . 를 사용하면 #if조건부 평가가 라이브러리의 컴파일 설정과 관련하여 수행됩니다. 이 Conditional속성을 사용하면 호출자의 컴파일 설정과 관련하여 조건부 평가가 수행됩니다.


답변

custom을 사용하여 네트워크 트래픽을 기록하는 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(...)