/// <summary> /// Appends formatted string to the given string builder. String will be fully escaped. /// </summary> /// <param name="sb">String builder to which string should be appended.</param> /// <param name="s">String which should be formatted and appended to the string builder.</param> /// <param name="quote">Indicates whether formatted string should be enclosed in double quotation marks (true) or not (false).</param> /// <param name="maxLength"> /// Maximum number of characters allowed to the formatter. Formatting will fail (and return false) /// if this number of characters is breached. Multi-lined formatters will ignore this parameter. /// Negative value indicates that formatter has unlimited space available. On output contains remaining number of characters available. /// </param> /// <returns> /// true if representation of <paramref name="arg" /> has been successfully appended to <paramref name="sb" /> /// within given number of allowed characters; otherwise false. /// </returns> private bool FormatString(StringBuilder sb, string s, bool quote, ref int maxLength) { var success = true; var originalLength = sb.Length; if (quote) { success = FormatInfoUtils.TryAppendChar(this, sb, '"', success, ref maxLength); } for (var i = 0; success && i < s.Length; i++) { success = FormatChar(sb, s[i], false, true, ref maxLength); } if (quote) { success = FormatInfoUtils.TryAppendChar(this, sb, '"', success, ref maxLength); } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Formats user friendly representation of the name of the given matrix or jagged array type. /// </summary> /// <param name="type">Type for which user friendly representation of the name is required.</param> /// <param name="instance"> /// Instance for which friendly type name is appended. /// This argument is used to gather additional information which might not be available from the type information. /// This argument may be null if instance is not available. /// </param> /// <param name="sb"> /// String builder to which user friendly representation of the name of <paramref name="type" /> is appended. /// If <paramref name="type" /> is null then nothing is appended to this string builder. /// </param> /// <param name="maxLength"> /// Maximum number of characters allowed to this method to append to string builder. Negative value indicates /// unlimited number of characters allowed. Method fails and returns false if it could not perform the task within given number of /// characters. /// On output contains remaining number of characters allowed. /// </param> /// <returns> /// true if method has successfully appended friendly name of the data type within given number of characters allowed; otherwise /// false. /// </returns> internal override bool AppendFriendlyTypeName(Type type, object instance, StringBuilder sb, ref int maxLength) { var success = true; var originalLength = sb.Length; if (type != null) { var elementType = GetElementType(type); if (elementType != null) { var sfi = new ScalarFormatInfo(); success = success && sfi.AppendFriendlyTypeName(elementType, null, sb, ref maxLength); } } var rows = 0; var lowCols = 0; var highCols = 0; if (instance != null) { GetDimensions((Array)instance, out rows, out lowCols, out highCols); } success = FormatInfoUtils.TryAppendChar(this, sb, '[', success, ref maxLength); if (instance != null) { success = FormatInfoUtils.TryAppendString(this, sb, rows.ToString("0"), success, ref maxLength); } success = FormatInfoUtils.TryAppendChar(this, sb, ']', success, ref maxLength); success = FormatInfoUtils.TryAppendChar(this, sb, '[', success, ref maxLength); if (instance != null) { success = FormatInfoUtils.TryAppendString(this, sb, lowCols.ToString("0"), success, ref maxLength); if (highCols != lowCols) { success = FormatInfoUtils.TryAppendChar(this, sb, '-', success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, highCols.ToString("0"), success, ref maxLength); } } success = FormatInfoUtils.TryAppendChar(this, sb, ']', success, ref maxLength); if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Formats friendly representation of the name of the given type. /// </summary> /// <param name="type">Type for which friendly representation of the name is required.</param> /// <param name="instance"> /// Instance for which friendly type name is appended. /// This argument is used to gather additional information which might not be available /// from the type information. This argument may be null if instance is not available. /// </param> /// <param name="sb"> /// String builder to which friendly name of <paramref name="type" /> is appended. /// If <paramref name="type" /> is null then nothing is appended to this string builder. /// </param> /// <param name="maxLength"> /// Maximum number of characters allowed to this method /// to append to string builder. Negative value indicates unlimited number of characters allowed. /// Method fails and returns false if it could not perform the task within given number /// of characters. On output contains remaining number of characters allowed. /// </param> /// <returns> /// true if method has successfully appended friendly name of the data type /// within given number of characters allowed; otherwise false. /// </returns> internal override bool AppendFriendlyTypeName(Type type, object instance, StringBuilder sb, ref int maxLength) { var success = true; var originalLength = sb.Length; if (type != null) { type = type.GetElementType(); // For arrays print element type rather than array type } if (success) { var sfi = new ScalarFormatInfo(this); success = sfi.AppendFriendlyTypeName(type, null, sb, ref maxLength); // Use scalar format info because it can write simple data types in a more compact way } // Now append dimensions of the array // If instance is null then dimensions cannot be determined and braces will remain empty, like int[]. // Otherwise, if instance is present, dimensions will be fully shown, like int[3, 4, 2] in case of three-dimensional array. success = FormatInfoUtils.TryAppendChar(this, sb, '[', success, ref maxLength); if (instance != null) { var dimensions = GetDimensions(instance); for (var i = 0; success && i < dimensions.Length; i++) { if (i > 0) { success = FormatInfoUtils.TryAppendString(this, sb, ", ", success, ref maxLength); } success = FormatInfoUtils.TryAppendString(this, sb, dimensions[i].ToString("0"), success, ref maxLength); } } success = FormatInfoUtils.TryAppendChar(this, sb, ']', success, ref maxLength); if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Converts the value of a specified object to an equivalent string representation using /// specified format and culture-specific formatting information. /// </summary> /// <param name="sb">String builder to which formatted string should be appended.</param> /// <param name="format">A format string containing formatting specifications.</param> /// <param name="arg">An object to format.</param> /// <param name="formatProvider">An object that supplies format information about the current instance.</param> /// <param name="maxLength"> /// Maximum number of characters allowed to the formatter. Formatting will fail (and return false) /// if this number of characters is breached. Multi-lined formatters will ignore this parameter. /// Negative value indicates that formatter has unlimited space available. On output contains remaining number of characters available. /// </param> /// <returns> /// true if representation of <paramref name="arg" /> has been successfully appended to <paramref name="sb" /> /// within given number of allowed characters; otherwise false. /// </returns> internal override bool Format(StringBuilder sb, string format, object arg, IFormatProvider formatProvider, ref int maxLength) { var success = true; var originalLength = sb.Length; if (PushCurrentObject(arg)) { if (ShowDataType) { var instanceType = GetInstanceType(arg); success = success && AppendFriendlyTypeName(instanceType, arg, sb, ref maxLength); } if (sb.Length > originalLength) { success = FormatInfoUtils.TryAppendChar(this, sb, ' ', success, ref maxLength); } success = FormatInfoUtils.TryAppendString(this, sb, FirstContainedValuePrefix, success, ref maxLength); if (arg != null) { IncIndentationLevel(true); var array = (Array)arg; var rows = array.GetLength(0); var cafi = new CompactArrayFormatInfo(this); cafi.ShowItemsOnly = true; cafi.FieldLength = GetMaxValueLength(array); var rowNumberFormatProvider = new ScalarFormatInfo(VerboseFormatInfo.SingleLinedFormat); rowNumberFormatProvider.ShowDataType = false; rowNumberFormatProvider.ShowInstanceName = false; if (IsMultiLinedFormat) { rowNumberFormatProvider.FieldLength = rowNumberFormatProvider.GetValueLength(rows); } for (var i = 0; i < rows; i++) { if (i == rows - 1) { DecIndentationLevel(); IncIndentationLevel(false); // There are no more rows in the matrix cafi.DecIndentationLevel(); cafi.IncIndentationLevel(false); } success = success && FormatLinePrefix(sb, true, i == rows - 1, false, 0, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, "Row ", success, ref maxLength); success = success && rowNumberFormatProvider.Format(sb, null, i, rowNumberFormatProvider, ref maxLength); success = FormatInfoUtils.TryAppendChar(this, sb, ' ', success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, FirstContainedValuePrefix, success, ref maxLength); // Now we should append row content, which is obtained differently in case of matrix and in case of jagged array if (array.Rank == 1) { // Array is jagged var row = (Array)array.GetValue(i); cafi.ShowLastDimension = false; success = success && cafi.Format(sb, null, row, cafi, ref maxLength); } else { // Array is a matrix cafi.HeadingIndices = new[] { i }; cafi.ShowLastDimension = true; success = success && cafi.Format(sb, null, array, cafi, ref maxLength); cafi.HeadingIndices = null; } success = FormatInfoUtils.TryAppendString(this, sb, LastContainedValueSuffix, success, ref maxLength); } DecIndentationLevel(); } success = FormatInfoUtils.TryAppendString(this, sb, LastContainedValueSuffix, success, ref maxLength); PopCurrentObject(); } else { success = success && FormatInfoUtils.ReportInfiniteLoop(sb, arg, InstanceName, ref maxLength); } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Converts the value of a specified object to an equivalent string representation using /// specified format and culture-specific formatting information. /// </summary> /// <param name="sb">String builder to which formatted string should be appended.</param> /// <param name="format">Format string containing formatting specifications.</param> /// <param name="arg">An object to format.</param> /// <param name="formatProvider">An object that supplies format information about the current instance.</param> /// <param name="maxLength"> /// Maximum number of characters allowed to the formatter. Formatting will fail (and return false) /// if this number of characters is breached. Multi-lined formatters will ignore this parameter. /// Negative value indicates that formatter has unlimited space available. On output contains remaining number of characters available. /// </param> /// <returns> /// true if representation of <paramref name="arg" /> has been successfully appended to <paramref name="sb" /> /// within given number of allowed characters; otherwise false. /// </returns> internal override bool Format(StringBuilder sb, string format, object arg, IFormatProvider formatProvider, ref int maxLength) { var success = true; var originalLength = sb.Length; if (PushCurrentObject(arg)) { if (ShowDataType) { success = success && AppendInstanceTypeName(arg, sb, ref maxLength); } if (!string.IsNullOrEmpty(InstanceName)) { var name = string.Format("{0}{1}{2}={2}", sb.Length > originalLength ? " " : "", InstanceName, IsMultiLinedFormat ? " " : ""); success = FormatInfoUtils.TryAppendString(this, sb, name, success, ref maxLength); } else if (sb.Length > originalLength) { success = FormatInfoUtils.TryAppendChar(this, sb, ' ', success, ref maxLength); } var argType = GetInstanceType(arg); if (arg == null) { success = FormatInfoUtils.TryAppendString(this, sb, FormatInfoUtils.DefaultNullFormatted, success, ref maxLength); } else if (arg is char) { success = success && FormatChar(sb, (char)arg, true, false, ref maxLength); } else if (arg is string) { success = success && FormatString(sb, (string)arg, true, ref maxLength); } else if (arg is Boolean) { success = FormatInfoUtils.TryAppendString(this, sb, ((bool)arg) ? "true" : "false", success, ref maxLength); } else if (argType.IsEnum) { var plainName = Enum.GetName(argType, arg); if (plainName != null) { success = FormatInfoUtils.TryAppendString(this, sb, plainName, success, ref maxLength); } else { success = success && AppendEnumFlags((Enum)arg, sb, ref maxLength); // arg is an OR-ed combination of values } } else { success = FormatInfoUtils.TryAppendString(this, sb, arg.ToString(), success, ref maxLength); } while (success && sb.Length - originalLength < _fieldLength) { success = FormatInfoUtils.TryAppendChar(this, sb, ' ', success, ref maxLength); } PopCurrentObject(); } else { success = success && FormatInfoUtils.ReportInfiniteLoop(sb, arg, InstanceName, ref maxLength); } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Appends names of enumeration constants that are present in the OR-ed value. /// </summary> /// <param name="value">Enumeration value which is possibly a combination of multiple OR-ed values.</param> /// <param name="sb">String builder to which enumeration value names should be appended.</param> /// <param name="maxLength"> /// Maximum number of characters allowed to the formatter. Formatting will fail (and return false) /// if this number of characters is breached. Multi-lined formatters will ignore this parameter. /// Negative value indicates that formatter has unlimited space available. On output contains remaining number of characters available. /// </param> /// <returns> /// true if representation of <paramref name="arg" /> has been successfully appended to <paramref name="sb" /> /// within given number of allowed characters; otherwise false. /// </returns> private bool AppendEnumFlags(Enum value, StringBuilder sb, ref int maxLength) { var success = true; var originalLength = sb.Length; var enumType = value.GetType(); var underlyingType = Enum.GetUnderlyingType(enumType); // The following code tries to recover flags in a flagged enum value // in .NET 4.0 this can be done much easier using Enum.HasFlag instance-level method, but with some unpredictable outcomes // e.g. if enumeration defines Left, Right and Both=Left | Right; then Both might be shown as Left | Right | Both which is avoided by this function var isInt64 = false; var isUint64 = false; Int64 int64Value = 0; UInt64 uint64Value = 0; if (underlyingType == typeof(sbyte) || underlyingType == typeof(Int16) || underlyingType == typeof(Int32) || underlyingType == typeof(Int64)) { isInt64 = true; int64Value = ((IConvertible)value).ToInt64(null); } else if (underlyingType == typeof(byte) || underlyingType == typeof(UInt16) || underlyingType == typeof(UInt32) || underlyingType == typeof(UInt64)) { isUint64 = true; uint64Value = ((IConvertible)value).ToUInt64(null); } Int64 constructedInt64Value = 0; UInt64 constructedUint64Value = 0; var values = Enum.GetValues(enumType); var constructionComplete = false; var flags = new List <object>(); // Enumeration values that are incorporated in OR-ed value foreach (var simpleValue in values) { if (isInt64) { var curInt64Value = ((IConvertible)simpleValue).ToInt64(null); if ((int64Value & curInt64Value) == curInt64Value && (constructedInt64Value & curInt64Value) != curInt64Value) { // simpleValue is part of the resulting OR-ed value and is not included in currently constructed value (or is not completely included) constructedInt64Value = constructedInt64Value | curInt64Value; flags.Add(simpleValue); if (constructedInt64Value == int64Value) { constructionComplete = true; break; } } } else if (isUint64) { var curUint64Value = ((IConvertible)simpleValue).ToUInt64(null); if ((uint64Value & curUint64Value) == curUint64Value && (constructedUint64Value & curUint64Value) != curUint64Value) { // simpleValue is part of the resulting OR-ed value and is not included in currently constructed value (or is not completely included) constructedUint64Value = constructedUint64Value | curUint64Value; flags.Add(simpleValue); if (constructedUint64Value == uint64Value) { constructionComplete = true; break; } } } } if (!constructionComplete) { success = FormatInfoUtils.TryAppendString(this, sb, value.ToString(), success, ref maxLength); // Append it as number or whatever Enum.ToString() makes out of this value } else { var isFirst = true; foreach (var simpleValue in flags) { if (!isFirst) { success = FormatInfoUtils.TryAppendChar(this, sb, '+', success, ref maxLength); } isFirst = false; success = FormatInfoUtils.TryAppendString(this, sb, Enum.GetName(enumType, simpleValue), success, ref maxLength); if (!success) { break; } } } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Converts the value of a specified object to an equivalent string representation using /// specified format and culture-specific formatting information. /// </summary> /// <param name="sb">String builder to which formatted string should be appended.</param> /// <param name="format">A format string containing formatting specifications.</param> /// <param name="arg">An object to format.</param> /// <param name="formatProvider">An object that supplies format information about the current instance.</param> /// <param name="maxLength"> /// Maximum number of characters allowed to the formatter. Formatting should fail (and return false) /// if this number of characters is breached. Multi-lined formatters should ignore this parameter. /// Negative value indicates that formatter has unlimited space available. On output contains remaining number of characters available. /// </param> /// <returns> /// true if representation of <paramref name="arg" /> has been successfully appended to <paramref name="sb" /> /// within given number of allowed characters; otherwise false. /// </returns> internal override bool Format(StringBuilder sb, string format, object arg, IFormatProvider formatProvider, ref int maxLength) { var success = true; var originalLength = sb.Length; if (PushCurrentObject(arg)) { if (arg == null) { success = FormatInfoUtils.TryAppendString(this, sb, FormatInfoUtils.DefaultNullFormatted, success, ref maxLength); } else { var keys = GetKeysCollection(arg); var keyType = GetDeclaredKeyValueType(arg, true); var valueType = GetDeclaredKeyValueType(arg, false); var sfi = new ScalarFormatInfo(this); success = success && sfi.AppendInstanceTypeName(arg, sb, ref maxLength); // Using scalar format info to append type name ensures that scalar types will be // represented with their short forms rather than CTS names which are less readable if (!string.IsNullOrEmpty(InstanceName)) { success = FormatInfoUtils.TryAppendSpaceIfNeeded(this, sb, success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, InstanceName, success, ref maxLength); } if (IsMultiLinedFormat) { success = FormatInfoUtils.TryAppendSpaceIfNeeded(this, sb, success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, "= ", success, ref maxLength); } else { success = FormatInfoUtils.TryAppendChar(this, sb, '=', success, ref maxLength); } success = FormatInfoUtils.TryAppendString(this, sb, FirstContainedValuePrefix, success, ref maxLength); if (MaximumDepth > 0) { MaximumDepth--; var enumerator = keys.GetEnumerator(); var isFirstValue = true; var key = new object[2]; var keyFetched = new bool[2]; keyFetched[0] = enumerator.MoveNext(); if (keyFetched[0]) { key[0] = enumerator.Current; keyFetched[1] = enumerator.MoveNext(); if (keyFetched[1]) { key[1] = enumerator.Current; } } VerboseFormatInfoBase containedItemsFormat = new VerboseFormatInfo(this); var itemPos = 0; while (keyFetched[0]) { IncIndentationLevel(keyFetched[1]); containedItemsFormat.IncIndentationLevel(keyFetched[1]); success = success && FormatLinePrefix(sb, isFirstValue, !keyFetched[1], false, 0, ref maxLength); isFirstValue = false; success = FormatInfoUtils.TryAppendString(this, sb, "Item[", success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, itemPos.ToString("0"), success, ref maxLength); itemPos++; success = FormatInfoUtils.TryAppendString(this, sb, "] = ", success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, FirstContainedValuePrefix, success, ref maxLength); containedItemsFormat.IncIndentationLevel(true); IncIndentationLevel(true); success = success && FormatLinePrefix(sb, true, false, false, 0, ref maxLength); containedItemsFormat.InstanceDataType = keyType; containedItemsFormat.InstanceName = "Key"; success = success && containedItemsFormat.Format(sb, null, key[0], containedItemsFormat, ref maxLength); DecIndentationLevel(); containedItemsFormat.DecIndentationLevel(); containedItemsFormat.IncIndentationLevel(false); IncIndentationLevel(false); var value = GetValue(arg, key[0]); success = success && FormatLinePrefix(sb, false, true, false, 0, ref maxLength); containedItemsFormat.InstanceDataType = valueType; containedItemsFormat.InstanceName = "Value"; success = success && containedItemsFormat.Format(sb, null, value, containedItemsFormat, ref maxLength); DecIndentationLevel(); containedItemsFormat.DecIndentationLevel(); success = FormatInfoUtils.TryAppendString(this, sb, LastContainedValueSuffix, success, ref maxLength); key[0] = key[1]; keyFetched[0] = keyFetched[1]; if (keyFetched[0]) { keyFetched[1] = enumerator.MoveNext(); if (keyFetched[1]) { key[1] = enumerator.Current; } } containedItemsFormat.DecIndentationLevel(); DecIndentationLevel(); } MaximumDepth++; } // if (MaximumDepth > 0) success = FormatInfoUtils.TryAppendString(this, sb, LastContainedValueSuffix, success, ref maxLength); } PopCurrentObject(); } else { success = success && FormatInfoUtils.ReportInfiniteLoop(sb, arg, InstanceName, ref maxLength); } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Appends all fields that should be placed before next contained value is appended to the output. /// In single-lined formats that will only be the field delimiter. /// In multi-lined formats that may include indentation strings. /// </summary> /// <param name="sb"> /// String builder which ends with a field after which strings that are used to /// delimit successive fields should be appended. /// </param> /// <param name="firstValueFollows"> /// Indicates whether next value to be formatted is the first contained value /// under the current instance (true) or other fields at the same level have already been appended to the output (false). /// </param> /// <param name="lastValueFollows"> /// Indicates whether next value is the last one (true) or there are more values to follow (false). /// Ignored if this format provider is single-lined. /// </param> /// <param name="skipRightMostIndentationString"> /// Indicates whether right-most indentation string should be replaced with normal indentation string /// (true) or not (false). This stands for last right most indentation string as well. /// </param> /// <param name="padLineToLength"> /// Indicates required length of the line in multi-lined formats. If string created by applying /// all prefixes and delimiters is shorter than this value then it is right-padded with blank spaces until this length is reached. /// </param> /// <param name="maxLength"> /// Maximum number of characters allowed to be appended to string builder by this function. /// Negative value indicates unlimited number. If this function cannot fit the content into this number of characters /// then it fails and returns false. On output contains remaining number of characters available. /// </param> /// <returns> /// true if function has successfully appended specified content to the string builder without breaching the allowed /// number of characters specified by parameter <paramref name="maxLength" />; otherwise false. /// </returns> internal bool FormatLinePrefix(StringBuilder sb, bool firstValueFollows, bool lastValueFollows, bool skipRightMostIndentationString, int padLineToLength, ref int maxLength) { var originalLength = sb.Length; var success = true; if (firstValueFollows && _isMultiLinedFormat) { success = FormatInfoUtils.TryAppendString(this, sb, Environment.NewLine, success, ref maxLength); } else if (!firstValueFollows) { success = FormatInfoUtils.TryAppendString(this, sb, _fieldDelimiter, success, ref maxLength); } if (_isMultiLinedFormat) { success = FormatInfoUtils.TryAppendString(this, sb, _linePrefix, success, ref maxLength); for (var i = 0; success && i < IndentationLevel; i++) { string indentString = null; string lastIndentString = null; if (IsIndentationLevelOccupied(i + 1)) { indentString = IndentationString; lastIndentString = LastIndentationString; } else { indentString = string.Empty; for (var j = 0; j < IndentationString.Length; j++) { if (IndentationString[j] == '\t') { indentString += '\t'; } else { indentString += ' '; } } lastIndentString = string.Empty; for (var j = 0; j < LastIndentationString.Length; j++) { if (LastIndentationString[j] == '\t') { lastIndentString += '\t'; } else { lastIndentString += ' '; } } } var rightMostIndentString = (skipRightMostIndentationString ? indentString : RightMostIndentationString); var lastRightMostIndentString = (skipRightMostIndentationString ? lastIndentString : LastRightMostIndentationString); if (lastValueFollows && i == IndentationLevel - 1) { success = FormatInfoUtils.TryAppendString(this, sb, lastRightMostIndentString ?? lastIndentString ?? rightMostIndentString ?? indentString, success, ref maxLength); } else if (lastValueFollows) { success = FormatInfoUtils.TryAppendString(this, sb, lastIndentString ?? indentString, success, ref maxLength); } else if (i == IndentationLevel - 1) { success = FormatInfoUtils.TryAppendString(this, sb, rightMostIndentString ?? indentString, success, ref maxLength); } else { success = FormatInfoUtils.TryAppendString(this, sb, indentString, success, ref maxLength); } } if (padLineToLength > 0) { var lineLength = GetCurrentLineLength(sb); while (success && lineLength++ < padLineToLength) { success = FormatInfoUtils.TryAppendChar(this, sb, ' ', success, ref maxLength); } } } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Appends formatted string representing part of the array provided, starting from specific location within the array. /// </summary> /// <param name="sb">String builder to which formatted string will be appended.</param> /// <param name="arg">Array which should be formatted into string which is appended to <paramref name="sb" />.</param> /// <param name="indices"> /// List of index values for dimensions iterated this far. In every call, this method will continue /// from location within the array indicated by this parameter. /// </param> /// <param name="maxLength"> /// Maximum number of characters allowed to the formatter. /// Single-lined formatting will fail (and return false) if this number of characters is breached. /// Multi-lined formatters ignore this parameter. Negative value indicates /// that formatter has unlimited space available. On output contains remaining number of characters available. /// </param> /// <returns> /// true if representation of <paramref name="arg" /> has been successfully appended to <paramref name="sb" /> /// within given number of allowed characters; otherwise false. /// </returns> private bool RecursiveAppendDimension(StringBuilder sb, Array arg, List <int> indices, ref int maxLength) { var success = true; var originalLength = sb.Length; var dimension = arg.GetLength(indices.Count); if (dimension > 0) { for (var i = 0; i < dimension; i++) { indices.Add(i); IncIndentationLevel(i < dimension - 1); success = success && FormatLinePrefix(sb, true, i == dimension - 1, false, 0, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, "Item[", success, ref maxLength); var firstIndex = true; foreach (var index in indices) { if (!firstIndex) { success = FormatInfoUtils.TryAppendString(this, sb, ", ", success, ref maxLength); } firstIndex = false; success = FormatInfoUtils.TryAppendString(this, sb, index.ToString("0"), success, ref maxLength); } success = FormatInfoUtils.TryAppendString(this, sb, "] ", success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, FirstContainedValuePrefix, success, ref maxLength); if (indices.Count < arg.Rank) { success = success && RecursiveAppendDimension(sb, arg, indices, ref maxLength); } else { var value = arg.GetValue(indices.ToArray()); var vfi = new VerboseFormatInfo(this); vfi.MaximumFormattedLength = FormatInfoUtils.CombineMaxFormattedLengths( RawMaximumFormattedLength, FormatInfoUtils.DefaultMaxFormattedLength); success = FormatInfoUtils.TryAppendChar(this, sb, ' ', success, ref maxLength); success = success && vfi.Format(sb, null, value, vfi, ref maxLength); } success = FormatInfoUtils.TryAppendString(this, sb, LastContainedValueSuffix, success, ref maxLength); DecIndentationLevel(); indices.RemoveAt(indices.Count - 1); } } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Converts the value of a specified object to an equivalent string representation using /// specified format and culture-specific formatting information. /// </summary> /// <param name="sb">String builder to which formatted string will be appended.</param> /// <param name="format">Format string containing formatting specifications.</param> /// <param name="arg">An object to format.</param> /// <param name="formatProvider">An object that supplies format information about the current instance.</param> /// <param name="maxLength"> /// Maximum number of characters allowed to the formatter. Formatting will fail (and return false) /// if this number of characters is breached. Multi-lined formatters will ignore this parameter. /// Negative value indicates that formatter has unlimited space available. /// On output contains remaining number of characters available. /// </param> /// <returns> /// true if representation of <paramref name="arg" /> has been successfully appended to <paramref name="sb" /> /// within given number of allowed characters; otherwise false. /// </returns> internal override bool Format(StringBuilder sb, string format, object arg, IFormatProvider formatProvider, ref int maxLength) { var success = true; var originalLength = sb.Length; if (PushCurrentObject(arg)) { if (ShowDataType) { success = success && AppendInstanceTypeName(arg, sb, ref maxLength); } if (ShowInstanceName && !string.IsNullOrEmpty(InstanceName)) { success = FormatInfoUtils.TryAppendSpaceIfNeeded(this, sb, success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, InstanceName, success, ref maxLength); if (IsMultiLinedFormat) { success = FormatInfoUtils.TryAppendString(this, sb, " = ", success, ref maxLength); } else { success = FormatInfoUtils.TryAppendChar(this, sb, '=', success, ref maxLength); } } else { success = FormatInfoUtils.TryAppendSpaceIfNeeded(this, sb, success, ref maxLength); } if (arg == null) { success = FormatInfoUtils.TryAppendString(this, sb, FormatInfoUtils.DefaultNullFormatted, success, ref maxLength); } else { success = FormatInfoUtils.TryAppendString(this, sb, FirstContainedValuePrefix, success, ref maxLength); if (MaximumDepth > 0) { MaximumDepth--; var members = ExtractMembers(arg); var vfi = new VerboseFormatInfo(this); vfi.ShowDataType = true; vfi.ShowInstanceName = true; for (var i = 0; success && i < members.Length; i++) { IncIndentationLevel(i < members.Length - 1); vfi.IncIndentationLevel(i < members.Length - 1); success = success && FormatLinePrefix(sb, i == 0, i == members.Length - 1, false, 0, ref maxLength); vfi.InstanceDataType = members[i].DataType; vfi.InstanceName = members[i].Name; success = success && vfi.Format(sb, format, members[i].Value, vfi, ref maxLength); vfi.DecIndentationLevel(); DecIndentationLevel(); } MaximumDepth++; } success = FormatInfoUtils.TryAppendString(this, sb, LastContainedValueSuffix, success, ref maxLength); } PopCurrentObject(); } else { success = success && FormatInfoUtils.ReportInfiniteLoop(sb, arg, InstanceName, ref maxLength); } if (!success) { sb.Length = originalLength; } return(success); }