다음을 통해 공유


DebuggerDisplay 특성(C#, Visual Basic, F#, C++/CLI)을 사용하여 표시할 내용을 디버거에 알립니다.

DebuggerDisplayAttribute 개체, 속성 또는 필드가 디버거 변수 창에 표시되는 방식을 제어합니다. 이 특성은 형식(클래스, 구조체, 열거형, 대리자)에 적용할 수 있지만 일반적으로 클래스 및 구조체에만 적용됩니다. 기본 형식에 적용된 경우 특성은 하위 클래스에도 적용됩니다.

DebuggerDisplay 특성에는 형식 인스턴스의 값 열에 표시할 문자열인 단일 인수가 있습니다. 이 문자열은 중괄호({})를 포함할 수 있습니다. 중괄호 쌍 내의 텍스트는 필드, 속성 또는 메서드로 평가됩니다.

클래스에 재정의된 ToString() 메서드가 있는 경우 디버거는 기본 {<typeName>}대신 재정의된 메서드를 사용합니다. 따라서 ToString() 메서드를 재정의한 경우 디버거는 기본 {<typeName>}대신 재정의된 메서드를 사용하며 DebuggerDisplay사용할 필요가 없습니다. 둘 다 사용하는 경우 DebuggerDisplay 특성이 재정의된 ToString() 메서드보다 우선합니다. 또한 DebuggerDisplay 특성은 서브클래스의 재정의된 ToString() 메서드보다 우선합니다.

디버거가 이 암시적 ToString() 호출을 평가하는지 여부는 도구/옵션/디버깅 대화 상자의 사용자 설정에 따라 달라집니다.

중요하다

도구/옵션/디버깅 대화 상자에서 변수 창 개체의 원시 구조 표시 확인란을 선택하면 DebuggerDisplay 특성이 무시됩니다.

메모

네이티브 코드의 경우 이 특성은 C++/CLI 코드에서만 지원됩니다.

다음 표에서는 DebuggerDisplay 특성 및 예제 출력을 사용할 수 있는 몇 가지 방법을 보여 줍니다.

속성 값 열에 표시되는 출력
[DebuggerDisplay("x = {x} y = {y}")]

xy필드가 있는 유형에 사용됩니다.
x = 5 y = 18
[DebuggerDisplay("String value is {getString()}")]매개 변수 구문은 언어마다 다를 수 있습니다. 따라서 주의해서 사용합니다. String value is [5, 6, 6]

DebuggerDisplay 명명된 매개 변수를 수락할 수도 있습니다.

매개 변수 목적
Name, Type 이러한 매개 변수는 변수 창의 이름형식 열에 영향을 줍니다. (생성자와 동일한 구문을 사용하여 문자열로 설정할 수 있습니다.) 이러한 매개 변수를 과도하게 사용하거나 잘못 사용하면 출력이 혼동될 수 있습니다.
Target, TargetTypeName 어셈블리 수준에서 특성을 사용할 때 대상 형식을 지정합니다.

autoexp.cs 파일은 어셈블리 수준에서 DebuggerDisplay 특성을 사용합니다. autoexp.cs 파일은 Visual Studio에서 .NET 개체에 사용하는 기본 확장을 결정합니다. autoexp.cs 파일을 검사하여 DebuggerDisplay 특성을 사용하는 방법의 예를 확인하거나 autoexp.cs 파일을 수정하고 컴파일하여 기본 확장을 변경할 수 있습니다. autoexp.cs 파일을 수정하기 전에 백업해야 합니다.

autoexp.cs 빌드하려면 VS2015용 개발자 명령 프롬프트를 열고 다음 명령을 실행합니다.

cd <directory containing autoexp.cs>
csc /t:library autoexp.cs

autoexp.dll 변경 내용은 다음 디버그 세션에서 적용됩니다.

DebuggerDisplay의 표현식 사용

DebuggerDisplay 특성의 중괄호 간에 일반 식을 사용할 수 있지만 이 방법은 사용하지 않는 것이 좋습니다.

DebuggerDisplay의 일반 식은 대상 형식의 현재 인스턴스에 대해서만 this 포인터에 암시적으로 액세스할 수 있습니다. 이 식은 별칭, 지역 변수 또는 포인터에 액세스할 수 없습니다. 식이 속성을 참조하는 경우, 해당 속성에 부여된 특성은 처리되지 않습니다. 예를 들어, 필드 count가 8이면 C# 코드 [DebuggerDisplay("Object {count - 2}")]은(는) Object 6을 표시합니다.

DebuggerDisplay에서 식을 사용하면 다음과 같은 문제가 발생할 수 있습니다.

  • 식 평가는 디버거에서 가장 비용이 많이 드는 작업이며 식이 표시될 때마다 계산됩니다. 이로 인해 코드 단계별 실행에서 성능 문제가 발생할 수 있습니다. 예를 들어 컬렉션 또는 목록의 값을 표시하는 데 사용되는 복합 식은 요소 수가 클 때 매우 느릴 수 있습니다.

  • 식은 식이 작성된 언어의 계산기가 아니라 현재 스택 프레임의 언어에 대한 식 계산기를 통해 계산됩니다. 이로 인해 언어가 다를 때 예측할 수 없는 결과가 발생할 수 있습니다.

  • 식을 평가하면 애플리케이션의 상태가 변경됩니다. 예를 들어 속성 값을 설정하는 식은 실행 코드의 속성 값을 변경합니다.

    식 계산의 가능한 문제를 줄이는 한 가지 방법은 작업을 수행하고 문자열을 반환하는 프라이빗 속성을 만드는 것입니다. 그러면 DebuggerDisplay 특성이 해당 비공개 프로퍼티의 값을 표시할 수 있습니다. 다음 예제에서는 이 패턴을 구현합니다.

[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class MyClass
{
    public int count { get; set; }
    public bool flag { get; set; }
    private string DebuggerDisplay
    {
        get
        {
            return string.Format("Object {0}", count - 2);
        }
    }
}

",nq" 접미사는 최종 값(nq = 따옴표 없음)을 표시할 때 식 계산기에서 따옴표를 제거하도록 지시합니다.

예시

다음 코드 예제에서는 DebuggerBrowsableDebuggerTypeProxy함께 DebuggerDisplay사용하는 방법을 보여 줍니다. 조사식 창과 같은 디버거 변수 창에서 볼 때 다음과 같은 확장이 생성됩니다.

이름 형식
열쇠 개체 {string}
3 개체 {int}
[DebuggerDisplay("{value}", Name = "{key}")]
internal class KeyValuePairs
{
    private IDictionary dictionary;
    private object key;
    private object value;
    public KeyValuePairs(IDictionary dictionary, object key, object value)
    {
        this.value = value;
        this.key = key;
        this.dictionary = dictionary;
    }

    public object Key
    {
        get { return key; }
        set
        {
            object tempValue = dictionary[key];
            dictionary.Remove(key);
            key = value;
            dictionary.Add(key, tempValue);
        }
    }

    public object Value
    {
        get { return this.value; }
        set
        {
            this.value = value;
            dictionary[key] = this.value;
        }
    }
}

[DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable
{
    public Hashtable hashtable;

    public MyHashtable()
    {
        hashtable = new Hashtable();
    }

    private string DebuggerDisplay { get { return "Count = " + hashtable.Count; } }

    private class HashtableDebugView
    {
        private MyHashtable myhashtable;
        public HashtableDebugView(MyHashtable myhashtable)
        {
            this.myhashtable = myhashtable;
        }

        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        public KeyValuePairs[] Keys
        {
            get
            {
                KeyValuePairs[] keys = new KeyValuePairs[myhashtable.hashtable.Count];

                int i = 0;
                foreach (object key in myhashtable.hashtable.Keys)
                {
                    keys[i] = new KeyValuePairs(myhashtable.hashtable, key, myhashtable.hashtable[key]);
                    i++;
                }
                return keys;
            }
        }
    }
}