/// <summary> /// Formats current Value according to the given format, specified by <see cref="System.Diagnostics.DebuggerDisplayAttribute"/>. /// </summary> /// <param name="debugFormat">Format to use</param> /// <returns>Formatted string.</returns> /// <remarks> /// Not all possible expressions are supported, but only a simple set. /// Otherwise we would have to support any C# expression. /// </remarks> static string FormatDebugValue(Thread evalThread, Value value, string debugFormat) { StringBuilder formattedOutput = new StringBuilder(); StringBuilder currentFieldName = new StringBuilder(); bool insideFieldName = false; bool ignoringRestOfExpression = false; bool insideMethodBrackets = false; bool isMethodName = false; bool escapeNextChar = false; for (int i = 0; i < debugFormat.Length; i++) { char thisChar = debugFormat[i]; if (!escapeNextChar && (thisChar == '{')) { insideFieldName = true; } else if (!escapeNextChar && (thisChar == '}')) { // Insert contents of specified member, if we can find it, otherwise we display "?" string memberValueStr = "?"; // Decide if we want a method or field/property Predicate <IUnresolvedMember> isNeededMember; if (isMethodName) { // We only support methods without parameters here! isNeededMember = m => (m.Name == currentFieldName.ToString()) && (m.SymbolKind == SymbolKind.Method) && (((IUnresolvedMethod)m).Parameters.Count == 0); } else { isNeededMember = m => (m.Name == currentFieldName.ToString()) && ((m.SymbolKind == SymbolKind.Field) || (m.SymbolKind == SymbolKind.Property)); } IMember member = value.type.GetMembers(isNeededMember).FirstOrDefault(); if (member != null) { Value memberValue = value.GetMemberValue(evalThread, member); memberValueStr = memberValue.InvokeToString(evalThread); } formattedOutput.Append(memberValueStr); insideFieldName = false; ignoringRestOfExpression = false; insideMethodBrackets = false; isMethodName = false; currentFieldName.Clear(); } else if (!escapeNextChar && (thisChar == '\\')) { // Next character will be escaped escapeNextChar = true; } else if (insideFieldName && (thisChar == '(')) { insideMethodBrackets = true; } else if ((thisChar == ')') && insideMethodBrackets) { insideMethodBrackets = false; isMethodName = true; // Everything following the brackets will be ignored ignoringRestOfExpression = true; } else if (insideFieldName && !Char.IsDigit(thisChar) && !Char.IsLetter(thisChar)) { // Char seems not to belong to a field name, ignore everything from now on ignoringRestOfExpression = true; } else { if (insideFieldName) { if (!ignoringRestOfExpression) { currentFieldName.Append(thisChar); } } else { formattedOutput.Append(thisChar); } escapeNextChar = false; } } return(formattedOutput.ToString()); }
public static string FormatValue(Value val) { if (val == null) { return null; } if (val.IsNull) { return "null"; } else if (val.Type.IsArray) { StringBuilder sb = new StringBuilder(); sb.Append(val.Type.Name); sb.Append(" {"); bool first = true; foreach(Value item in val.GetArrayElements()) { if (!first) sb.Append(", "); first = false; sb.Append(FormatValue(item)); } sb.Append("}"); return sb.ToString(); } else if (val.Type.GetInterface(typeof(ICollection).FullName) != null) { StringBuilder sb = new StringBuilder(); sb.Append(val.Type.Name); sb.Append(" {"); val = val.GetPermanentReference(); int count = (int)val.GetMemberValue("Count").PrimitiveValue; for(int i = 0; i < count; i++) { if (i > 0) sb.Append(", "); DebugPropertyInfo itemProperty = (DebugPropertyInfo)val.Type.GetProperty("Item"); Value item = val.GetPropertyValue(itemProperty, Eval.CreateValue(val.AppDomain, i)); sb.Append(FormatValue(item)); } sb.Append("}"); return sb.ToString(); } else if (val.Type.FullName == typeof(char).FullName) { return "'" + val.PrimitiveValue.ToString() + "'"; } else if (val.Type.FullName == typeof(string).FullName) { return "\"" + val.PrimitiveValue.ToString() + "\""; } else if (val.Type.IsPrimitive) { return val.PrimitiveValue.ToString(); } else { return val.InvokeToString(); } }