Существует ли метод для визуализации объекта с использованием DebuggerDisplayAttribute

У меня есть несколько классов, которые украшены DebuggerDisplayAttribute.

Я хочу иметь возможность добавлять операторы трассировки в модульные тесты, которые будут отображать экземпляры этих классов.

Существует ли в.NET Framework метод, который будет отображать объект, отформатированный с использованием DebuggerDisplayAttribute (или использовать метод.ToString(), если не определен DebuggerDisplayAttribute)?

РЕДАКТИРОВАТЬ

Чтобы уточнить, я надеялся, что в Framework может быть что-то встроено. Я знаю, что могу получить свойство Value из DebuggerDisplayAttribute, но затем мне нужно отформатировать мой экземпляр, используя строку формата, представленную DebuggerDisplayAttribute.Value.

Если бы я свернул свой собственный, я бы предусмотрел метод расширения по следующим направлениям:

public string FormatDebugDisplay(this object value)
{
    DebugDisplayAttribute attribute = ... get the attribute for value ...
    if (attribute = null) return value.ToString();

    string formatString = attribute.Value;

    ??? How do I format value using formatString ???
    return SomeFormatMethod(formatString, value);
}

3 ответа

Решение

Это может быть неплохо - но строка формата DebuggerDisplayAttribute оценивается отладчиком так же, как он вычисляет выражения, которые вы вводите в окнах Watch или Immediate. Вот почему вы можете поместить произвольные выражения в фигурные скобки, как {FirstName + " " + LastName},

Поэтому, чтобы оценить их в своем коде, вам необходимо встроить отладчик Visual Studio в ваше приложение. Вероятно, не произойдет. (Гринь)

Лучше всего, вероятно, взять всю логику форматирования, которая в настоящее время находится в строке формата DebuggerDisplay, и вместо этого сделать ее методом. Тогда вы можете вызывать этот метод из своего кода. Ваш атрибут DebuggerDisplay в итоге ничего не делает, кроме вызова метода.

[DebuggerDisplay("{Inspect()}")]
public class MyClass {
    public string Inspect() { ... }
}

Этот метод не реализует точно то, что DebuggerDisplayAttribute предоставляет в отладчике, но это то, что я использовал в своем коде. Он охватывает около 90% (или более) случаев, с которыми мы сталкиваемся в нашей базе кода. Если вы исправите это, чтобы охватить еще больше случаев, я хотел бы увидеть ваши улучшения!

    public static string ToDebuggerString(this object @this)
    {
        var display = @this.GetType().GetCustomAttributes(typeof (DebuggerDisplayAttribute),false).FirstOrDefault() as DebuggerDisplayAttribute;
        if (display == null)
            return @this.ToString();

        var format = display.Value;
        var builder = new StringBuilder();
        for (var index = 0; index < format.Length; index++)
        {
            if (format[index] == '{')
            {
                var close = format.IndexOf('}', index);
                if (close > index)
                {
                    index++;
                    var name = format.Substring(index, close - index);
                    var property = @this.GetType().GetProperty(name);
                    if (property != null)
                    {
                        var value = property.GetValue(@this, null).ToString();
                        builder.Append(value);
                        index += name.Length;
                    }
                }
            }
            else
                builder.Append(format[index]);
        }
        return builder.ToString();
    }

DebuggerDisplayAttribute имеет свойство Value, которое возвращает то, что вы хотите.

Таким образом, вы могли бы использовать что-то вроде этого:

var attribute = obj.GetType().
    GetCustomAttributes(typeof(DebuggerDisplayAttribute), false);
return (attribute == null) ? obj.ToString() : attribute.Value;

Вы могли бы даже поместить это в метод расширения:

public static string ToDebugString(this object obj)
{
    var attribute = obj.GetType().
        GetCustomAttributes(typeof(DebuggerDisplayAttribute), false);
    return (attribute == null) ? obj.ToString() : attribute.Value;
}

Вы можете вызвать его на каждом объекте: myObject.ToDebugString()

Другие вопросы по тегам