internal static void ValidateDebuggerDisplayReferences(object obj)
{
// Get the DebuggerDisplayAttribute for obj
var attrs =
obj.GetType().GetTypeInfo().CustomAttributes
.Where(a => a.AttributeType == typeof(DebuggerDisplayAttribute))
.ToArray();
if (attrs.Length != 1)
{
throw new InvalidOperationException(
string.Format("Expected one DebuggerDisplayAttribute on {0}.", obj));
}
var cad = (CustomAttributeData)attrs[0];
// Get the text of the DebuggerDisplayAttribute
string attrText = (string)cad.ConstructorArguments[0].Value;
// Parse the text for all expressions
var references = new List<string>();
int pos = 0;
while (true)
{
int openBrace = attrText.IndexOf('{', pos);
if (openBrace < pos) break;
int closeBrace = attrText.IndexOf('}', openBrace);
if (closeBrace < openBrace) break;
string reference = attrText.Substring(openBrace + 1, closeBrace - openBrace - 1).Replace(",nq", "");
pos = closeBrace + 1;
references.Add(reference);
}
if (references.Count == 0)
{
throw new InvalidOperationException(
string.Format("The DebuggerDisplayAttribute for {0} doesn't reference any expressions.", obj));
}
// Make sure that each referenced expression is a simple field or property name, and that we can
// invoke the property's get accessor or read from the field.
foreach (var reference in references)
{
PropertyInfo pi = GetProperty(obj, reference);
if (pi != null)
{
object ignored = pi.GetValue(obj, null);
continue;
}
FieldInfo fi = GetField(obj, reference);
if (fi != null)
{
object ignored = fi.GetValue(obj);
continue;
}
throw new InvalidOperationException(
string.Format("The DebuggerDisplayAttribute for {0} contains the expression \"{1}\".", obj, reference));
}
}