DefaultRenderer.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. #region Apache License
  2. //
  3. // Licensed to the Apache Software Foundation (ASF) under one or more
  4. // contributor license agreements. See the NOTICE file distributed with
  5. // this work for additional information regarding copyright ownership.
  6. // The ASF licenses this file to you under the Apache License, Version 2.0
  7. // (the "License"); you may not use this file except in compliance with
  8. // the License. You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. #endregion
  19. using System;
  20. using System.Text;
  21. using System.IO;
  22. using System.Collections;
  23. using log4net.Util;
  24. namespace log4net.ObjectRenderer
  25. {
  26. /// <summary>
  27. /// The default object Renderer.
  28. /// </summary>
  29. /// <remarks>
  30. /// <para>
  31. /// The default renderer supports rendering objects and collections to strings.
  32. /// </para>
  33. /// <para>
  34. /// See the <see cref="RenderObject"/> method for details of the output.
  35. /// </para>
  36. /// </remarks>
  37. /// <author>Nicko Cadell</author>
  38. /// <author>Gert Driesen</author>
  39. public sealed class DefaultRenderer : IObjectRenderer
  40. {
  41. #region Constructors
  42. /// <summary>
  43. /// Default constructor
  44. /// </summary>
  45. /// <remarks>
  46. /// <para>
  47. /// Default constructor
  48. /// </para>
  49. /// </remarks>
  50. public DefaultRenderer()
  51. {
  52. }
  53. #endregion
  54. #region Implementation of IObjectRenderer
  55. /// <summary>
  56. /// Render the object <paramref name="obj"/> to a string
  57. /// </summary>
  58. /// <param name="rendererMap">The map used to lookup renderers</param>
  59. /// <param name="obj">The object to render</param>
  60. /// <param name="writer">The writer to render to</param>
  61. /// <remarks>
  62. /// <para>
  63. /// Render the object <paramref name="obj"/> to a string.
  64. /// </para>
  65. /// <para>
  66. /// The <paramref name="rendererMap"/> parameter is
  67. /// provided to lookup and render other objects. This is
  68. /// very useful where <paramref name="obj"/> contains
  69. /// nested objects of unknown type. The <see cref="M:RendererMap.FindAndRender(object)"/>
  70. /// method can be used to render these objects.
  71. /// </para>
  72. /// <para>
  73. /// The default renderer supports rendering objects to strings as follows:
  74. /// </para>
  75. /// <list type="table">
  76. /// <listheader>
  77. /// <term>Value</term>
  78. /// <description>Rendered String</description>
  79. /// </listheader>
  80. /// <item>
  81. /// <term><c>null</c></term>
  82. /// <description>
  83. /// <para>"(null)"</para>
  84. /// </description>
  85. /// </item>
  86. /// <item>
  87. /// <term><see cref="Array"/></term>
  88. /// <description>
  89. /// <para>
  90. /// For a one dimensional array this is the
  91. /// array type name, an open brace, followed by a comma
  92. /// separated list of the elements (using the appropriate
  93. /// renderer), followed by a close brace.
  94. /// </para>
  95. /// <para>
  96. /// For example: <c>int[] {1, 2, 3}</c>.
  97. /// </para>
  98. /// <para>
  99. /// If the array is not one dimensional the
  100. /// <c>Array.ToString()</c> is returned.
  101. /// </para>
  102. /// </description>
  103. /// </item>
  104. /// <item>
  105. /// <term><see cref="IEnumerable"/>, <see cref="ICollection"/> &amp; <see cref="IEnumerator"/></term>
  106. /// <description>
  107. /// <para>
  108. /// Rendered as an open brace, followed by a comma
  109. /// separated list of the elements (using the appropriate
  110. /// renderer), followed by a close brace.
  111. /// </para>
  112. /// <para>
  113. /// For example: <c>{a, b, c}</c>.
  114. /// </para>
  115. /// <para>
  116. /// All collection classes that implement <see cref="ICollection"/> its subclasses,
  117. /// or generic equivalents all implement the <see cref="IEnumerable"/> interface.
  118. /// </para>
  119. /// </description>
  120. /// </item>
  121. /// <item>
  122. /// <term><see cref="DictionaryEntry"/></term>
  123. /// <description>
  124. /// <para>
  125. /// Rendered as the key, an equals sign ('='), and the value (using the appropriate
  126. /// renderer).
  127. /// </para>
  128. /// <para>
  129. /// For example: <c>key=value</c>.
  130. /// </para>
  131. /// </description>
  132. /// </item>
  133. /// <item>
  134. /// <term>other</term>
  135. /// <description>
  136. /// <para><c>Object.ToString()</c></para>
  137. /// </description>
  138. /// </item>
  139. /// </list>
  140. /// </remarks>
  141. public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
  142. {
  143. if (rendererMap == null)
  144. {
  145. throw new ArgumentNullException("rendererMap");
  146. }
  147. if (obj == null)
  148. {
  149. writer.Write(SystemInfo.NullText);
  150. return;
  151. }
  152. Array objArray = obj as Array;
  153. if (objArray != null)
  154. {
  155. RenderArray(rendererMap, objArray, writer);
  156. return;
  157. }
  158. // Test if we are dealing with some form of collection object
  159. IEnumerable objEnumerable = obj as IEnumerable;
  160. if (objEnumerable != null)
  161. {
  162. // Get a collection interface if we can as its .Count property may be more
  163. // performant than getting the IEnumerator object and trying to advance it.
  164. ICollection objCollection = obj as ICollection;
  165. if (objCollection != null && objCollection.Count == 0)
  166. {
  167. writer.Write("{}");
  168. return;
  169. }
  170. // This is a special check to allow us to get the enumerator from the IDictionary
  171. // interface as this guarantees us DictionaryEntry objects. Note that in .NET 2.0
  172. // the generic IDictionary<> interface enumerates KeyValuePair objects rather than
  173. // DictionaryEntry ones. However the implementation of the plain IDictionary
  174. // interface on the generic Dictionary<> still returns DictionaryEntry objects.
  175. IDictionary objDictionary = obj as IDictionary;
  176. if (objDictionary != null)
  177. {
  178. RenderEnumerator(rendererMap, objDictionary.GetEnumerator(), writer);
  179. return;
  180. }
  181. RenderEnumerator(rendererMap, objEnumerable.GetEnumerator(), writer);
  182. return;
  183. }
  184. IEnumerator objEnumerator = obj as IEnumerator;
  185. if (objEnumerator != null)
  186. {
  187. RenderEnumerator(rendererMap, objEnumerator, writer);
  188. return;
  189. }
  190. if (obj is DictionaryEntry)
  191. {
  192. RenderDictionaryEntry(rendererMap, (DictionaryEntry)obj, writer);
  193. return;
  194. }
  195. string str = obj.ToString();
  196. writer.Write( (str==null) ? SystemInfo.NullText : str );
  197. }
  198. #endregion
  199. /// <summary>
  200. /// Render the array argument into a string
  201. /// </summary>
  202. /// <param name="rendererMap">The map used to lookup renderers</param>
  203. /// <param name="array">the array to render</param>
  204. /// <param name="writer">The writer to render to</param>
  205. /// <remarks>
  206. /// <para>
  207. /// For a one dimensional array this is the
  208. /// array type name, an open brace, followed by a comma
  209. /// separated list of the elements (using the appropriate
  210. /// renderer), followed by a close brace. For example:
  211. /// <c>int[] {1, 2, 3}</c>.
  212. /// </para>
  213. /// <para>
  214. /// If the array is not one dimensional the
  215. /// <c>Array.ToString()</c> is returned.
  216. /// </para>
  217. /// </remarks>
  218. private void RenderArray(RendererMap rendererMap, Array array, TextWriter writer)
  219. {
  220. if (array.Rank != 1)
  221. {
  222. writer.Write(array.ToString());
  223. }
  224. else
  225. {
  226. writer.Write(array.GetType().Name + " {");
  227. int len = array.Length;
  228. if (len > 0)
  229. {
  230. rendererMap.FindAndRender(array.GetValue(0), writer);
  231. for(int i=1; i<len; i++)
  232. {
  233. writer.Write(", ");
  234. rendererMap.FindAndRender(array.GetValue(i), writer);
  235. }
  236. }
  237. writer.Write("}");
  238. }
  239. }
  240. /// <summary>
  241. /// Render the enumerator argument into a string
  242. /// </summary>
  243. /// <param name="rendererMap">The map used to lookup renderers</param>
  244. /// <param name="enumerator">the enumerator to render</param>
  245. /// <param name="writer">The writer to render to</param>
  246. /// <remarks>
  247. /// <para>
  248. /// Rendered as an open brace, followed by a comma
  249. /// separated list of the elements (using the appropriate
  250. /// renderer), followed by a close brace. For example:
  251. /// <c>{a, b, c}</c>.
  252. /// </para>
  253. /// </remarks>
  254. private void RenderEnumerator(RendererMap rendererMap, IEnumerator enumerator, TextWriter writer)
  255. {
  256. writer.Write("{");
  257. if (enumerator != null && enumerator.MoveNext())
  258. {
  259. rendererMap.FindAndRender(enumerator.Current, writer);
  260. while (enumerator.MoveNext())
  261. {
  262. writer.Write(", ");
  263. rendererMap.FindAndRender(enumerator.Current, writer);
  264. }
  265. }
  266. writer.Write("}");
  267. }
  268. /// <summary>
  269. /// Render the DictionaryEntry argument into a string
  270. /// </summary>
  271. /// <param name="rendererMap">The map used to lookup renderers</param>
  272. /// <param name="entry">the DictionaryEntry to render</param>
  273. /// <param name="writer">The writer to render to</param>
  274. /// <remarks>
  275. /// <para>
  276. /// Render the key, an equals sign ('='), and the value (using the appropriate
  277. /// renderer). For example: <c>key=value</c>.
  278. /// </para>
  279. /// </remarks>
  280. private void RenderDictionaryEntry(RendererMap rendererMap, DictionaryEntry entry, TextWriter writer)
  281. {
  282. rendererMap.FindAndRender(entry.Key, writer);
  283. writer.Write("=");
  284. rendererMap.FindAndRender(entry.Value, writer);
  285. }
  286. }
  287. }