| #region Apache License |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to you under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #endregion |
| |
| using System; |
| using System.Text; |
| using System.IO; |
| using System.Collections; |
| |
| using log4net.Util; |
| |
| namespace log4net.ObjectRenderer |
| { |
| /// <summary> |
| /// The default object Renderer. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The default renderer supports rendering objects and collections to strings. |
| /// </para> |
| /// <para> |
| /// See the <see cref="RenderObject"/> method for details of the output. |
| /// </para> |
| /// </remarks> |
| /// <author>Nicko Cadell</author> |
| /// <author>Gert Driesen</author> |
| public sealed class DefaultRenderer : IObjectRenderer |
| { |
| #region Constructors |
| |
| /// <summary> |
| /// Default constructor |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Default constructor |
| /// </para> |
| /// </remarks> |
| public DefaultRenderer() |
| { |
| } |
| |
| #endregion |
| |
| #region Implementation of IObjectRenderer |
| |
| /// <summary> |
| /// Render the object <paramref name="obj"/> to a string |
| /// </summary> |
| /// <param name="rendererMap">The map used to lookup renderers</param> |
| /// <param name="obj">The object to render</param> |
| /// <param name="writer">The writer to render to</param> |
| /// <remarks> |
| /// <para> |
| /// Render the object <paramref name="obj"/> to a string. |
| /// </para> |
| /// <para> |
| /// The <paramref name="rendererMap"/> parameter is |
| /// provided to lookup and render other objects. This is |
| /// very useful where <paramref name="obj"/> contains |
| /// nested objects of unknown type. The <see cref="M:RendererMap.FindAndRender(object)"/> |
| /// method can be used to render these objects. |
| /// </para> |
| /// <para> |
| /// The default renderer supports rendering objects to strings as follows: |
| /// </para> |
| /// <list type="table"> |
| /// <listheader> |
| /// <term>Value</term> |
| /// <description>Rendered String</description> |
| /// </listheader> |
| /// <item> |
| /// <term><c>null</c></term> |
| /// <description> |
| /// <para>"(null)"</para> |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term><see cref="Array"/></term> |
| /// <description> |
| /// <para> |
| /// For a one dimensional array this is the |
| /// array type name, an open brace, followed by a comma |
| /// separated list of the elements (using the appropriate |
| /// renderer), followed by a close brace. |
| /// </para> |
| /// <para> |
| /// For example: <c>int[] {1, 2, 3}</c>. |
| /// </para> |
| /// <para> |
| /// If the array is not one dimensional the |
| /// <c>Array.ToString()</c> is returned. |
| /// </para> |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term><see cref="IEnumerable"/>, <see cref="ICollection"/> & <see cref="IEnumerator"/></term> |
| /// <description> |
| /// <para> |
| /// Rendered as an open brace, followed by a comma |
| /// separated list of the elements (using the appropriate |
| /// renderer), followed by a close brace. |
| /// </para> |
| /// <para> |
| /// For example: <c>{a, b, c}</c>. |
| /// </para> |
| /// <para> |
| /// All collection classes that implement <see cref="ICollection"/> its subclasses, |
| /// or generic equivalents all implement the <see cref="IEnumerable"/> interface. |
| /// </para> |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term><see cref="DictionaryEntry"/></term> |
| /// <description> |
| /// <para> |
| /// Rendered as the key, an equals sign ('='), and the value (using the appropriate |
| /// renderer). |
| /// </para> |
| /// <para> |
| /// For example: <c>key=value</c>. |
| /// </para> |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term>other</term> |
| /// <description> |
| /// <para><c>Object.ToString()</c></para> |
| /// </description> |
| /// </item> |
| /// </list> |
| /// </remarks> |
| public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer) |
| { |
| if (rendererMap == null) |
| { |
| throw new ArgumentNullException("rendererMap"); |
| } |
| |
| if (obj == null) |
| { |
| writer.Write(SystemInfo.NullText); |
| return; |
| } |
| |
| Array objArray = obj as Array; |
| if (objArray != null) |
| { |
| RenderArray(rendererMap, objArray, writer); |
| return; |
| } |
| |
| // Test if we are dealing with some form of collection object |
| IEnumerable objEnumerable = obj as IEnumerable; |
| if (objEnumerable != null) |
| { |
| // Get a collection interface if we can as its .Count property may be more |
| // performant than getting the IEnumerator object and trying to advance it. |
| ICollection objCollection = obj as ICollection; |
| if (objCollection != null && objCollection.Count == 0) |
| { |
| writer.Write("{}"); |
| return; |
| } |
| |
| // This is a special check to allow us to get the enumerator from the IDictionary |
| // interface as this guarantees us DictionaryEntry objects. Note that in .NET 2.0 |
| // the generic IDictionary<> interface enumerates KeyValuePair objects rather than |
| // DictionaryEntry ones. However the implementation of the plain IDictionary |
| // interface on the generic Dictionary<> still returns DictionaryEntry objects. |
| IDictionary objDictionary = obj as IDictionary; |
| if (objDictionary != null) |
| { |
| RenderEnumerator(rendererMap, objDictionary.GetEnumerator(), writer); |
| return; |
| } |
| |
| RenderEnumerator(rendererMap, objEnumerable.GetEnumerator(), writer); |
| return; |
| } |
| |
| IEnumerator objEnumerator = obj as IEnumerator; |
| if (objEnumerator != null) |
| { |
| RenderEnumerator(rendererMap, objEnumerator, writer); |
| return; |
| } |
| |
| if (obj is DictionaryEntry) |
| { |
| RenderDictionaryEntry(rendererMap, (DictionaryEntry)obj, writer); |
| return; |
| } |
| |
| string str = obj.ToString(); |
| writer.Write( (str==null) ? SystemInfo.NullText : str ); |
| } |
| |
| #endregion |
| |
| /// <summary> |
| /// Render the array argument into a string |
| /// </summary> |
| /// <param name="rendererMap">The map used to lookup renderers</param> |
| /// <param name="array">the array to render</param> |
| /// <param name="writer">The writer to render to</param> |
| /// <remarks> |
| /// <para> |
| /// For a one dimensional array this is the |
| /// array type name, an open brace, followed by a comma |
| /// separated list of the elements (using the appropriate |
| /// renderer), followed by a close brace. For example: |
| /// <c>int[] {1, 2, 3}</c>. |
| /// </para> |
| /// <para> |
| /// If the array is not one dimensional the |
| /// <c>Array.ToString()</c> is returned. |
| /// </para> |
| /// </remarks> |
| private void RenderArray(RendererMap rendererMap, Array array, TextWriter writer) |
| { |
| if (array.Rank != 1) |
| { |
| writer.Write(array.ToString()); |
| } |
| else |
| { |
| writer.Write(array.GetType().Name + " {"); |
| int len = array.Length; |
| |
| if (len > 0) |
| { |
| rendererMap.FindAndRender(array.GetValue(0), writer); |
| for(int i=1; i<len; i++) |
| { |
| writer.Write(", "); |
| rendererMap.FindAndRender(array.GetValue(i), writer); |
| } |
| } |
| writer.Write("}"); |
| } |
| } |
| |
| /// <summary> |
| /// Render the enumerator argument into a string |
| /// </summary> |
| /// <param name="rendererMap">The map used to lookup renderers</param> |
| /// <param name="enumerator">the enumerator to render</param> |
| /// <param name="writer">The writer to render to</param> |
| /// <remarks> |
| /// <para> |
| /// Rendered as an open brace, followed by a comma |
| /// separated list of the elements (using the appropriate |
| /// renderer), followed by a close brace. For example: |
| /// <c>{a, b, c}</c>. |
| /// </para> |
| /// </remarks> |
| private void RenderEnumerator(RendererMap rendererMap, IEnumerator enumerator, TextWriter writer) |
| { |
| writer.Write("{"); |
| |
| if (enumerator != null && enumerator.MoveNext()) |
| { |
| rendererMap.FindAndRender(enumerator.Current, writer); |
| |
| while (enumerator.MoveNext()) |
| { |
| writer.Write(", "); |
| rendererMap.FindAndRender(enumerator.Current, writer); |
| } |
| } |
| |
| writer.Write("}"); |
| } |
| |
| /// <summary> |
| /// Render the DictionaryEntry argument into a string |
| /// </summary> |
| /// <param name="rendererMap">The map used to lookup renderers</param> |
| /// <param name="entry">the DictionaryEntry to render</param> |
| /// <param name="writer">The writer to render to</param> |
| /// <remarks> |
| /// <para> |
| /// Render the key, an equals sign ('='), and the value (using the appropriate |
| /// renderer). For example: <c>key=value</c>. |
| /// </para> |
| /// </remarks> |
| private void RenderDictionaryEntry(RendererMap rendererMap, DictionaryEntry entry, TextWriter writer) |
| { |
| rendererMap.FindAndRender(entry.Key, writer); |
| writer.Write("="); |
| rendererMap.FindAndRender(entry.Value, writer); |
| } |
| } |
| } |