Reputation: 29997
In Visual Studio, is it possible to customize the order in which properties are displayed when inspected in the debugger?
Here's an example of a class where I'd really like StartDate and EndDate to appear next to each other, even though they are separated alphabetically .
Other debugger options are customizable through attributes like the DebuggerDisplayAttribute
, so I was hopeful that another such attribute would exist for DisplayOrder.
[DebuggerDisplay("{Name}")]
public class Rule
{
public string Name;
public int MaxAge;
public DateTime StartDate;
public DateTime EndDate;
}
In an ideal world, I'd like the ability to order the properties in the inspector in the order that I have defined on the class (even if that requires setting an debugger order attribute incrementally on each property) so the display would look like this:
Upvotes: 9
Views: 2375
Reputation: 771
Pinnable Properties in VS2019+ are a way to go currently, since you can pin your properties in correct order using the button inside the datatip.
However, in a more general, reusable approach, the [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
attribute can be used on an array of ordered property name and value pairs. This enables the debug view to 'flatten' the array root, listing the properties in correct order.
Further expanding on KyleMit's answer, and using reflection to load the list of members and fields, makes such a debug view reusable:
[DebuggerDisplay("{Name}")]
[DebuggerTypeProxy(typeof(OrderedPropertiesView))]
public class Rule
{
public string Name;
public int MaxAge;
public DateTime StartDate;
public DateTime EndDate;
}
public class OrderedPropertiesView
{
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public SimpleProperty[] Properties { get; }
public OrderedPropertiesView(object input)
{
this.Properties = input.GetType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Select(prop => new SimpleProperty(prop, input))
.ToArray();
}
[DebuggerDisplay("{Value}", Name = "{PropertyName,nq}")]
public class SimpleProperty
{
public SimpleProperty(MemberInfo member, object input)
{
this.Value = GetValue(member, input);
this.PropertyName = member.Name;
}
private object GetValue(MemberInfo member, object input)
{
switch (member)
{
case FieldInfo fi: return fi.GetValue(input);
case PropertyInfo pi: return pi.GetValue(input);
default: return null;
}
}
public object Value { get; internal set; }
public string PropertyName { get; internal set; }
}
}
Which looks like this in the debugger:
The order of properties and fields might not be guaranteed with reflection, but since the view is only for debugging purposes, it should be enough. If not, Properties
array can be constructed manually, limiting the reusability. In either case, Properties
are not really properties, therefore expanding the SimpleProperty
datatip looks like this:
Notice that the property inspector can only be used in the expanded
SimpleProperty.Value
, which might be an inconvenience.
Upvotes: 9
Reputation: 29997
Just to run out the ball on JCL's suggestion to use #if DEBUG
with a caluclated property. If you wanted some extra information in the debugger, you could add a field only when in debug mode like this:
[DebuggerDisplay("{Name}")]
public class Rule
{
public string Name;
public int MaxAge;
public DateTime StartDate;
public DateTime EndDate;
#if DEBUG
private string DateRange
{
get { return StartDate.ToString("dd/MM/yyyy") + " - "+
EndDate.ToString("dd/MM/yyyy");
}
}
#endif
}
Which would look like this:
This gets information presented together, but will still add noise to the inspector.
Upvotes: 4
Reputation: 29997
Just to run out the ball on JCL's suggestion to use DebuggerTypeProxyAttribute
, you could add an internal class or a public class to act as a container for the debug view
You could use numbers to force the ordering of the the properties on the debugger view class without changing the API or performance of the runtime code.
Here's what the class would look like with the DebuggerTypeProxy:
[DebuggerDisplay("{Name}")]
[DebuggerTypeProxy(typeof (RuleDebugView))]
public class Rule
{
public string Name;
public int MaxAge;
public DateTime StartDate;
public DateTime EndDate;
internal class RuleDebugView
{
public string _1_Name;
public int _2_MaxAge;
public DateTime _3_StartDate;
public DateTime _4_EndDate;
public RuleDebugView(Rule rule)
{
this._1_Name = rule.Name;
this._2_MaxAge = rule.MaxAge;
this._3_StartDate = rule.StartDate;
this._4_EndDate = rule.EndDate;
}
}
}
Which would look like this in the debugger:
It's not the cleanest thing in the world, but it does do a little.
Upvotes: 2
Reputation: 49988
You could right click on the variables and 'Add Watch' and put them in order there.
Upvotes: 2