I was working on a data synchronizing application the other day. I needed to write to a file for the export, write to a string builder for logging and analysis, and write to the console for debugging. I know that it's pretty common that I'll need to write to more than 1 text stream at the same time, so I figured I could write a quick proxy application to write to a collection of TextWriters.Please comment on this post and let me know how this TextWriterProxy article helped you.Here's what I came up with:
1 using System.Collections.Generic;
2 using System.Text;
3 using System.IO;
4
5 namespace ESG.Utilities
6 { 7 public class TextWriterProxy : TextWriter
8 { 9 // store TextWriters here
10 private List<TextWriter> _writers = new List<TextWriter>();
11
12 #region Properties
13
14 /// <summary>
15 /// This property returns Encoding.Default. The TextWriters in the
16 /// TextWriterProxy collection can have any encoding. However, this
17 /// property is required.
18 /// </summary>
19 public override Encoding Encoding { get { return Encoding.Default; } } 20
21 /// <summary>
22 /// Gets or sets the line terminator string used by the TextWriters in
23 /// the TextWriterProxy collection.
24 /// </summary>
25 public override string NewLine
26 { 27 get
28 { 29 return base.NewLine;
30 }
31
32 set
33 { 34 foreach (TextWriter tw in _writers)
35 tw.NewLine = value;
36
37 base.NewLine = value;
38 }
39 }
40
41 #endregion
42
43 #region Methods
44
45 /// <summary>
46 /// Add a new TextWriter to the TextWriterProxy collection. Setting properties
47 /// or calling methods on the TextWriterProxy will perform the same action on
48 /// each TextWriter in the collection.
49 /// </summary>
50 /// <param name="writer">The TextWriter to add to the collection</param>
51 public void Add(TextWriter writer)
52 { 53 // don't add a TextWriter that's already in the collection
54 if (!_writers.Contains(writer))
55 _writers.Add(writer);
56 }
57
58 /// <summary>
59 /// Remove a TextWriter from the TextWriterProxy collection.
60 /// </summary>
61 /// <param name="writer">The TextWriter to remove from the collection</param>
62 /// <returns>True if the TextWriter was found and removed; False if not.</returns>
63 public bool Remove(TextWriter writer)
64 { 65 return _writers.Remove(writer);
66 }
67
68
69 // this is the only Write method that needs to be overridden
70 // because all of the Write methods in a TextWriter ultimately
71 // end up calling Write(char)
72
73 /// <summary>
74 /// Write a character to the text stream of each TextWriter in the
75 /// TextWriterProxy collection.
76 /// </summary>
77 /// <param name="value">The char to write</param>
78 public override void Write(char value)
79 { 80 foreach (TextWriter tw in _writers)
81 tw.Write(value);
82
83 base.Write(value);
84 }
85
86 /// <summary>
87 /// Closes the TextWriters in the TextWriterProxy as well as the
88 /// TextWriterProxy instance and releases any system resources
89 /// associated with them.
90 /// </summary>
91 public override void Close()
92 { 93 foreach (TextWriter tw in _writers)
94 tw.Close();
95
96 base.Close();
97 }
98
99 /// <summary>
100 /// Releases all resources used by the TextWriterProxy and by the
101 /// TextWriters in the TextWriterProxy collection.
102 /// </summary>
103 /// <param name="disposing">Pertains only to the TextWriterProxy instance:
104 /// true to release both managed and unmanaged resources; false to release
105 /// only unmanaged resources.</param>
106 protected override void Dispose(bool disposing)
107 { 108 foreach (TextWriter tw in _writers)
109 tw.Dispose();
110
111 base.Dispose(disposing);
112 }
113
114 /// <summary>
115 /// Clears all buffers for each TextWriter in the TextWriterProxy
116 /// collection and causes all buffered data to be written
117 /// to the underlying device.
118 /// </summary>
119 public override void Flush()
120 { 121 foreach (TextWriter tw in _writers)
122 tw.Flush();
123
124 base.Flush();
125 }
126
127 #endregion
128 }
129 }
So far, it works great. It cleans up a lot of my code and gives me the option to write to any number of TextWriters with only one call. Further, if you are calling a method that takes a TextWriter as a parameter, you can pass the TextWriterProxy to it because it extends the TextWriter class. Here's what the usage syntax looks like:
1 // create a TextWriterProxy instance
2 TextWriterProxy proxy = new TextWriterProxy();
3
4 // add the Console.Out TextWriter
5 proxy.Add(Console.Out);
6
7 // you can still write directly to console
8 Console.WriteLine(string.Empty.PadRight(80, '='));
9
10 // add a StreamWriter for a FileStream
11 FileStream fs = new FileStream("C:\\TestExportFileAutoGen.abx", FileMode.Create); 12 StreamWriter resultWriter = new StreamWriter(fs);
13 proxy.Add(resultWriter);
14
15 // add a StringWriter for a StringBuilder
16 StringBuilder sb = new StringBuilder();
17 StringWriter resultStringWriter = new StringWriter(sb);
18 proxy.Add(resultStringWriter);
19
20 // call a method that takes a TextWriter
21 ClientSync.GenerateSessionDataExport("Sync.ServerExport", proxy); 22
23 // write directly to the TextWriterProxy
24 proxy.WriteLine("Export Complete!"); 25
26 // close all of my writers
27 proxy.Close();
And there you have it. A TextWriterProxy class to write to multiple TextWriters at once.
I really appreciate
comments so please feel free to comment on my posts. Whether you agree or disagree, I'd love to hear from you. Also, feel free to link back to your own blog in your comments. You can even
subscribe to an RSS feed of the comments on this thread.
© 2008 , D. Patrick Caldwell, President,
Autopilot Consulting, LLC