/// <summary> /// Iterates through all values in the matrix or jagged array and finds maximum length required /// to show any of the values contained. /// </summary> /// <param name="array">Matrix or jagged array through which this method will iterate.</param> /// <returns>Number of characters sufficient to receive any formatted value contained in <paramref name="array" />.</returns> private int GetMaxValueLength(Array array) { var maxLength = 0; if (IsMultiLinedFormat) { var sfi = new ScalarFormatInfo(this); sfi.ShowDataType = false; sfi.ShowInstanceName = false; if (array.Rank == 2) { maxLength = sfi.GetMaxValueLength(array.GetEnumerator()); } else { // In jagged array we have to iterate through rows manually var rowsEnumerator = array.GetEnumerator(); while (rowsEnumerator.MoveNext()) { var row = (Array)rowsEnumerator.Current; var curMaxLength = sfi.GetMaxValueLength(row.GetEnumerator()); maxLength = Math.Max(maxLength, curMaxLength); } } } return(maxLength); }
/// <summary> /// Iterates through all values in the matrix or jagged array and finds maximum length required /// to show any of the values contained. /// </summary> /// <param name="array">Matrix or jagged array through which this method will iterate.</param> /// <returns>Number of characters sufficient to receive any formatted value contained in <paramref name="array" />.</returns> private int GetMaxValueLength(Array array) { var maxLength = 0; if (IsMultiLinedFormat) { var sfi = new ScalarFormatInfo(this); sfi.ShowDataType = false; sfi.ShowInstanceName = false; if (array.Rank == 2) { maxLength = sfi.GetMaxValueLength(array.GetEnumerator()); } else { // In jagged array we have to iterate through rows manually var rowsEnumerator = array.GetEnumerator(); while (rowsEnumerator.MoveNext()) { var row = (Array) rowsEnumerator.Current; var curMaxLength = sfi.GetMaxValueLength(row.GetEnumerator()); maxLength = Math.Max(maxLength, curMaxLength); } } } return maxLength; }
/// <summary> /// Formats user friendly representation of the name of the given 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.IsArray && type.GetArrayRank() == 1) { // This var elementType = type.GetElementType(); var sfi = new ScalarFormatInfo(this); success = success && sfi.AppendFriendlyTypeName(elementType, null, sb, ref maxLength); // This will append compact name for scalar types var ar = (Array)instance; var dimension = string.Format("[{0}]", ar.GetLength(0)); success = FormatInfoUtils.TryAppendString(this, sb, dimension, success, ref maxLength); } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Iterates through values that will be formatted in order to determine whether /// field length should be set to some specific value in order to align values better. /// </summary> /// <param name="sb"> /// String builder which can be conveniently used to format value. /// This function will return the string builder into present state on output. /// </param> private void UpdateFieldLength(StringBuilder sb) { if (IsMultiLinedFormat && _fieldLength <= 0 && _maxLineLength > 0) { // Field length will be updated only in multi-lined formats and only if not already set to positive value from outside. var maxLength = 0; var totalLength = 0; var enumerator = GetEnumerator(); var sfi = new ScalarFormatInfo(this); sfi.FieldLength = 0; sfi.ShowDataType = false; sfi.ShowInstanceName = false; var isFirstField = true; while (enumerator.MoveNext()) { var fieldLength = sfi.GetValueLength(enumerator.Current, sb); maxLength = Math.Max(maxLength, fieldLength); totalLength += (!isFirstField ? 1 : 0) + fieldLength; // Each but the first value is prefixed with a white space of length 1 isFirstField = false; } if (totalLength > _maxLineLength) { _fieldLength = maxLength; // Field length is set only if total contents of the array will breach the maximum allowed line length } // and consequently values should be aligned } }
/// <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> /// Gets value indicating whether this format provider can be applied to specified data type or not. /// This format provider is applicable to matrices (arrays of rank 2) and to jagged arrays, but only /// if element type is supported by ScalarFormatInfo format provider. /// </summary> /// <param name="dataType">Data type agianst which this format provider is tested.</param> /// <returns>true if this format provider is applicable; otherwise false.</returns> internal override bool IsFormatApplicable(Type dataType) { var elementType = GetElementType(dataType); var applicable = false; if (elementType != null) { // Existence of elementType proves that dataType is matrix or jagged array var sfi = new ScalarFormatInfo(this); applicable = sfi.IsFormatApplicable(elementType); } return(applicable); }
/// <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> /// Gets value indicating whether current format provider is applicable to format strings /// that represent instances of given data type. This format provider is applicable if /// data type is an array of values to which ScalarFormatInfo format provider is applicable. /// This format provider can also be applied to last dimension of a multi-dimensional array /// if specified so by the internal properties. /// </summary> /// <param name="dataType">Data type for which current format provider is tested.</param> /// <returns> /// true if current format provider is capable to format string representing instance /// of given data type; otherwise false. /// </returns> internal override bool IsFormatApplicable(Type dataType) { var applicable = false; if (dataType != null && dataType.IsArray) { if (_showLastDimension || dataType.GetArrayRank() == 1) { var elementType = dataType.GetElementType(); var sfi = new ScalarFormatInfo(this); if (sfi.IsFormatApplicable(elementType)) { applicable = true; } } } return(applicable); }
/// <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> /// 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; var formatters = new List<VerboseFormatInfoBase>(); var singleLinedFormat = SingleLinedFormat; if (arg != null || InstanceDataType != null) { var type = GetInstanceType(arg); var sfi = new ScalarFormatInfo(this); sfi.MaximumFormattedLength = maxLength; if (sfi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedSfi = new ScalarFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedSfi); singleLinedSfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedSfi); } formatters.Add(sfi); } if (formatters.Count == 0) { var dfi = new DictionaryFormatInfo(this); dfi.MaximumFormattedLength = maxLength; if (dfi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedDfi = new DictionaryFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedDfi); singleLinedDfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedDfi); } formatters.Add(dfi); } } if (formatters.Count == 0) { var cmfi = new CompactMatrixFormatInfo(this); cmfi.MaximumFormattedLength = maxLength; if (cmfi.IsFormatApplicable(type)) { //if (IsMultiLinedFormat) // Uncomment these lines to enable inlining compactly presented matrices; that operation is not suggested //{ // CompactMatrixFormatInfo singleLinedCmfi = new CompactMatrixFormatInfo(this); // FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedCmfi); // singleLinedCmfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); // formatters.Add(singleLinedCmfi); //} formatters.Add(cmfi); } } if (formatters.Count == 0) { var cafi = new CompactArrayFormatInfo(this); cafi.MaximumFormattedLength = maxLength; if (cafi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedCafi = new CompactArrayFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedCafi); singleLinedCafi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedCafi); } formatters.Add(cafi); } } if (formatters.Count == 0) { var afi = new ArrayFormatInfo(this); afi.MaximumFormattedLength = maxLength; if (afi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedAfi = new ArrayFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedAfi); singleLinedAfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedAfi); } formatters.Add(afi); } } if (formatters.Count == 0) { var efi = new EnumerableFormatInfo(this); efi.MaximumFormattedLength = maxLength; if (efi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedEfi = new EnumerableFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedEfi); singleLinedEfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedEfi); } formatters.Add(efi); } } if (formatters.Count == 0) { if (IsMultiLinedFormat) { var singleLinedGfi = new GeneralFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedGfi); singleLinedGfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedGfi); } var gfi = new GeneralFormatInfo(this); gfi.MaximumFormattedLength = maxLength; formatters.Add(gfi); } } if (formatters.Count > 0) { success = success && FormatInfoUtils.BestTryFormat(sb, format, arg, formatters, ref maxLength); } if (!success) { sb.Length = originalLength; } return success; }
/// <summary> /// Copy constructor which initializes new instance and copies common values from another instance of this class. /// </summary> /// <param name="other">Instance from which common values should be copied.</param> public ScalarFormatInfo(ScalarFormatInfo other) : base(other) { _fieldLength = other._fieldLength; }
/// <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">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> /// 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> /// Gets value indicating whether this format provider can be applied to specified data type or not. /// This format provider is applicable to matrices (arrays of rank 2) and to jagged arrays, but only /// if element type is supported by ScalarFormatInfo format provider. /// </summary> /// <param name="dataType">Data type agianst which this format provider is tested.</param> /// <returns>true if this format provider is applicable; otherwise false.</returns> internal override bool IsFormatApplicable(Type dataType) { var elementType = GetElementType(dataType); var applicable = false; if (elementType != null) { // Existence of elementType proves that dataType is matrix or jagged array var sfi = new ScalarFormatInfo(this); applicable = sfi.IsFormatApplicable(elementType); } return applicable; }
/// <summary> /// Converts the value of a specified array 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. /// </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; var array = (Array)arg; var rank = array.Rank; if (rank > 1 || PushCurrentObject(arg)) { _currentInstance = array; var prevFieldLength = _fieldLength; UpdateFieldLength(sb); // Autonomously updates field length if that will help better format values from the array if (!_showItemsOnly && ShowDataType) { success = success && AppendInstanceTypeName(arg, sb, ref maxLength); success = FormatInfoUtils.TryAppendSpaceIfNeeded(this, sb, success, ref maxLength); success = FormatInfoUtils.TryAppendString(this, sb, FirstContainedValuePrefix, success, ref maxLength); } var enumerator = GetEnumerator(); var sfi = new ScalarFormatInfo(this); sfi.ShowDataType = false; sfi.ShowInstanceName = false; sfi.FieldLength = _fieldLength; var linePrefixLength = GetCurrentLineLength(sb); var lineStartPos = sb.Length; var isFirstValueInLine = true; var repeatLastValue = false; while (success && (repeatLastValue || enumerator.MoveNext())) { // At every position it might happen that line should be broken and formatting continued on the following line var prevLineLength = sb.Length - lineStartPos; string delimiter = null; if (isFirstValueInLine) { delimiter = ""; } else if (IsMultiLinedFormat) { delimiter = " "; } else { delimiter = FieldDelimiter; } success = FormatInfoUtils.TryAppendString(this, sb, delimiter, success, ref maxLength); success = success && sfi.Format(sb, null, enumerator.Current, sfi, ref maxLength); isFirstValueInLine = false; repeatLastValue = false; if (IsMultiLinedFormat && _maxLineLength > 0 && sb.Length - lineStartPos > _maxLineLength && !isFirstValueInLine) { // Maximum line length has been breached in the multi-lined format // As a consequence, last value should be deleted from output, new line should be started and last value formatted again sb.Length = prevLineLength + lineStartPos; success = success && FormatLinePrefix(sb, true, false, true, linePrefixLength, ref maxLength); lineStartPos = sb.Length; repeatLastValue = true; isFirstValueInLine = true; } } if (!_showItemsOnly) { success = FormatInfoUtils.TryAppendString(this, sb, LastContainedValueSuffix, success, ref maxLength); } _fieldLength = prevFieldLength; // Restore field length to value before this method was called if (rank == 1) { PopCurrentObject(); } } else { success = success && FormatInfoUtils.ReportInfiniteLoop(sb, arg, InstanceName, ref maxLength); } if (!success) { sb.Length = originalLength; } return(success); }
/// <summary> /// Copy constructor which initializes new instance and copies common values from another instance of this class. /// </summary> /// <param name="other">Instance from which common values should be copied.</param> public ScalarFormatInfo(ScalarFormatInfo other) : base(other) { _fieldLength = other._fieldLength; }
/// <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 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; var formatters = new List <VerboseFormatInfoBase>(); var singleLinedFormat = SingleLinedFormat; if (arg != null || InstanceDataType != null) { var type = GetInstanceType(arg); var sfi = new ScalarFormatInfo(this); sfi.MaximumFormattedLength = maxLength; if (sfi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedSfi = new ScalarFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedSfi); singleLinedSfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedSfi); } formatters.Add(sfi); } if (formatters.Count == 0) { var dfi = new DictionaryFormatInfo(this); dfi.MaximumFormattedLength = maxLength; if (dfi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedDfi = new DictionaryFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedDfi); singleLinedDfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedDfi); } formatters.Add(dfi); } } if (formatters.Count == 0) { var cmfi = new CompactMatrixFormatInfo(this); cmfi.MaximumFormattedLength = maxLength; if (cmfi.IsFormatApplicable(type)) { //if (IsMultiLinedFormat) // Uncomment these lines to enable inlining compactly presented matrices; that operation is not suggested //{ // CompactMatrixFormatInfo singleLinedCmfi = new CompactMatrixFormatInfo(this); // FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedCmfi); // singleLinedCmfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); // formatters.Add(singleLinedCmfi); //} formatters.Add(cmfi); } } if (formatters.Count == 0) { var cafi = new CompactArrayFormatInfo(this); cafi.MaximumFormattedLength = maxLength; if (cafi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedCafi = new CompactArrayFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedCafi); singleLinedCafi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedCafi); } formatters.Add(cafi); } } if (formatters.Count == 0) { var afi = new ArrayFormatInfo(this); afi.MaximumFormattedLength = maxLength; if (afi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedAfi = new ArrayFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedAfi); singleLinedAfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedAfi); } formatters.Add(afi); } } if (formatters.Count == 0) { var efi = new EnumerableFormatInfo(this); efi.MaximumFormattedLength = maxLength; if (efi.IsFormatApplicable(type)) { if (IsMultiLinedFormat) { var singleLinedEfi = new EnumerableFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedEfi); singleLinedEfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedEfi); } formatters.Add(efi); } } if (formatters.Count == 0) { if (IsMultiLinedFormat) { var singleLinedGfi = new GeneralFormatInfo(this); FormatInfoUtils.CopyFormatting(singleLinedFormat, singleLinedGfi); singleLinedGfi.CombineMaximumFormattedLength(FormatInfoUtils.DefaultMaxFormattedLength); formatters.Add(singleLinedGfi); } var gfi = new GeneralFormatInfo(this); gfi.MaximumFormattedLength = maxLength; formatters.Add(gfi); } } if (formatters.Count > 0) { success = success && FormatInfoUtils.BestTryFormat(sb, format, arg, formatters, 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 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); }