1:   // --------------------------------------------------------------------------
2:   // (c) Copyright Bill Dawson 2002
3:   // http://www.BillDawson.com
4:   //
5:   // You are free to use this source code in your projects.  Please leave
6:   // this copyright message intact.
7:   // --------------------------------------------------------------------------
8:  
9:   namespace com.billdawson.dotnet.utils
10:   {
11:       using System;
12:       using System.Reflection;
13:       using Microsoft.CSharp;
14:       using Microsoft.VisualBasic;
15:       using Microsoft.JScript;
16:       using System.CodeDom;
17:       using System.CodeDom.Compiler;
18:       using System.Collections;
19:       using System.IO;
20:       
21:       /// <summary>
22:       /// Static methods to overcome limitations of public fields by turning them
23:       /// into public properties of a new wrapper class that redirects calls to 
24:       /// the orig class fields.
25:       /// </summary>
26:       /// <remarks>For example, you may be using a class that you cannot
27:       /// or do not wish to change, but that has one or more public fields
28:       /// that you would rather access as public properties.  You might
29:       /// want this so that you can bind the type directly as a data item
30:       /// in a DataGrid.  This class's Wrap methods can be used to create
31:       /// a second class that wraps the first and uses public properties to
32:       /// access the original class's public fields.
33:       /// </remarks>
34:       public class Field2PropWrap
35:       {
36:           /// <summary>
37:           /// Code providers for these languages can be instantiated by 
38:           /// this library.
39:           /// </summary>
40:           /// <remarks>However, if you have a different code provider
41:           /// you can also use the Transform method that accepts a provider
42:           /// directly as a parameter.
43:           /// </remarks>
44:           public enum TransformLanguage{
45:               CSharp,
46:               VB,
47:               JScript
48:           }
49:           
50:           /// <summary>
51:           /// Creates a new type based on the passed type.  This new type will
52:           /// have public properties named the same as the original type's
53:           /// public fields.  Code inside the new type will redirect property calls
54:           /// to the orig type's fields.  New code is written to stream.
55:           /// </summary>
56:           /// <param name="origtype">The original type that will be wrapped.</param>
57:           /// <param name="newNamespace">Namespace string for the new type.</param>
58:           /// <param name="yourLanguage">Any CodeDomProvider.  This allows you to use languages other than the three recognized internally.</param>
59:           /// <param name="writer">A text writer to an output stream to which the new code will be sent.</param>
60:           public static void Wrap(Type origtypestring newNamespaceCodeDomProvider yourLanguageTextWriter writer)
61:           {
62:               string origTypeFullName origtype.FullName;
63:               string origTypeShortName origtype.Name;
64:               
65:               ArrayList fields new System.Collections.ArrayList();
66:           
67:               // find all public fields; these are the things we want
68:               // to turn into public properties in our new type.
69:               foreach(FieldInfo fi in origtype.GetFields( ))
70:               {
71:                   if (fi.IsPublic
72:                       fields.Add(fi);                
73:               }
74:               
75:           
76:               if (fields.Count==0// there aren't any; nothing to do
77:                   throw new TypeHasNoPublicFieldsException(origTypeFullName);
78:               
79:               // transform ArrayList to typed array
80:               FieldInfo[] fis null;
81:               fis = (FieldInfo[])fields.ToArray(typeof(FieldInfo));
82:               
83:               // The System.CodeDom stuff we need to generate code
84:               CodeNamespace ns new CodeNamespace(newNamespace);
85:  
86:               // new type has same name as old but will be put 
87:               // in the new namespace
88:               CodeTypeDeclaration newtype 
89:                   new CodeTypeDeclarationorigTypeShortName );
90:               
91:               // private var for new class, to hold instance
92:               // of old class
93:               CodeMemberField pvar =
94:                       new CodeMemberField(origTypeFullName"_wrapped");
95:               pvar.AttributesMemberAttributes.Private ;
96:               newtype.Members.Add(pvar);
97:               
98:               // create a reference expression to reference that
99:               // _wrapped variable later in order to assign to it.
100:               CodeVariableReferenceExpression pvarRef =
101:                       new CodeVariableReferenceExpression(pvar.Name);
102:               
103:               
104:               // Constructor that accepts the old type
105:               // and sets private var to the old type
106:               CodeParameterDeclarationExpression param =
107:                       new CodeParameterDeclarationExpression(origtype,"orig");
108:               CodeConstructor constructor new CodeConstructor();
109:               constructor.Parameters.Add(param);
110:               constructor.Attributes MemberAttributes.Public;
111:               
112:               // Create a reference to that parameter as a variable so we can
113:               // use it in an assignment statement
114:               CodeVariableReferenceExpression paramRef =
115:                       new CodeVariableReferenceExpression(param.Name);
116:  
117:               // Make the assignment statement that is inside the constructor
118:               // i.e., in C# , _wrapped = orig;
119:               constructor.Statements.Add(new CodeAssignStatement(pvarRef,paramRef));
120:               
121:               // Add the constructor as a member to the new type
122:               newtype.Members.Add(constructor);
123:               
124:               // add our new type to the new namespace.
125:               ns.Types.Add(newtype);
126:               
127:               // add public properties where old class has fields
128:               foreach(FieldInfo fi in fis)
129:               {
130:                   // for each pulbic field in the orig, make a public property
131:                   // in thenew
132:                   CodeMemberProperty prop new CodeMemberProperty();            
133:                   // give new property same name and type as old field.
134:                   prop.Name fi.Name;
135:                   prop.Type new CodeTypeReferencefi.FieldType );
136:                   prop.Attributes MemberAttributes.Public;
137:                   
138:                   //  reference to orig class variable is pvarref from above
139:                   // (referencing private variable we named "_wrapped")
140:                   // Here we reference its public field that has the
141:                   // same name as the public property we are creating
142:                   CodeFieldReferenceExpression refToOldField =
143:                       new CodeFieldReferenceExpression(pvarReffi.Name);
144:                   
145:                   // a return expression, simply returns the value of
146:                   // the base field, for the Get statement
147:                   CodeMethodReturnStatement ret 
148:                           new CodeMethodReturnStatement(refToOldField);
149:                   
150:                   // the property get accessor
151:                   prop.GetStatements.Add(ret);
152:                   
153:                   // an assignment expression for the set accessor
154:                   prop.SetStatements.Add
155:                            new CodeAssignStatement(
156:                               refToOldField,new CodePropertySetValueReferenceExpression()));
157:                   
158:                   // add this property member to the new type
159:                   newtype.Members.Add(prop);
160:               }            
161:               
162:               // generate the code
163:               generateNamespaceToStream(nswriteryourLanguage);
164:               
165:           }
166:  
167:           /// <summary>
168:           /// Creates a new type based on the passed type.  This new type will
169:           /// have public properties named the same as the original type's
170:           /// public fields.  Code inside the new type will redirect property calls
171:           /// to the orig type's fields.  Returns the new code as a string.
172:           /// </summary>
173:           /// <param name="origtype">The original type that will be wrapped.</param>
174:           /// <param name="newNamespace">Namespace string for the new type.</param>
175:           /// <param name="yourLanguage">Any CodeDomProvider.  This allows you to use languages other than the three recognized internally.</param>
176:           /// <returns>String, the generated code for the new class.</returns>
177:           public static string Wrap(Type origtypestring newNamespaceCodeDomProvider yourLanguage)
178:           {
179:               MemoryStream ms new MemoryStream();
180:               TextWriter tw new StreamWriter(ms);            
181:               Wrap(origtypenewNamespaceyourLanguagetw);
182:               ms.Position=0;
183:               StreamReader sr new StreamReader(ms);
184:               string result sr.ReadToEnd();
185:               sr.Close();
186:               ms.Close();
187:               return result;
188:           }
189:  
190:           /// <summary>
191:           /// Creates a new type based on the passed type.  This new type will
192:           /// have public properties named the same as the original type's
193:           /// public fields.  Code inside the new type will redirect property calls
194:           /// to the orig type's fields.  Returns the new code as a string.
195:           /// </summary>
196:           /// <param name="origtype">The original type that will be wrapped.</param>
197:           /// <param name="newNamespace">Namespace string for the new type.</param>
198:           /// <param name="language">The supported language enum member.</param>
199:           /// <returns>String, the generated code for the new class.</returns>
200:           public static string Transform(Type origtypestring newNamespaceTransformLanguage language)
201:           {
202:               CodeDomProvider provider getProviderFromEnum(language);
203:               return Wrap(origtypenewNamespaceprovider);
204:           }
205:  
206:           /// <summary>
207:           /// Creates a new type based on the passed type.  This new type will
208:           /// have public properties named the same as the original type's
209:           /// public fields.  Code inside the new type will redirect property calls
210:           /// to the orig type's fields.  Writes the new code to a stream.
211:           /// </summary>
212:           /// <param name="origtype">The original type that will be wrapped.</param>
213:           /// <param name="newNamespace">Namespace string for the new type.</param>
214:           /// <param name="language">The supported language enum member.</param>
215:           /// <param name="writer">A TextWriter to an output stream to which the new code will be sent.</param>        
216:           public static void Wrap(Type origtypestring newNamespaceTransformLanguage languageTextWriter writer)
217:           {
218:               CodeDomProvider provider getProviderFromEnum(language);
219:               Wrap(origtypenewNamespaceproviderwriter);
220:           }
221:           
222:           private static CodeDomProvider getProviderFromEnum(TransformLanguage tl)
223:           {
224:               CodeDomProvider provider=null;
225:               if (tl==TransformLanguage.VB)
226:                   provider new VBCodeProvider();
227:               else if (tl==TransformLanguage.CSharp)
228:                   provider new CSharpCodeProvider();
229:               else if (tl==TransformLanguage.JScript)
230:                   provider new JScriptCodeProvider();
231:               else
232:                   throw new UnknownLanguageException("unk");
233:               return provider;
234:           }
235:           
236:           private static void generateNamespaceToStream(CodeNamespace nsStream streamCodeDomProvider provider)
237:           {
238:               generateNamespaceToStream(nsnew StreamWriter(stream), provider);
239:           }
240:           
241:           private static void generateNamespaceToStream(CodeNamespace nsTextWriter twCodeDomProvider provider)        
242:           {
243:               CodeCompileUnit compileUnit new CodeCompileUnit();
244:               compileUnit.Namespaces.Add(ns);
245:               ICodeGenerator generator provider.CreateGenerator();
246:               CodeGeneratorOptions options new CodeGeneratorOptions();
247:               options.BracingStyle "C";
248:               generator.GenerateCodeFromCompileUnit(compileUnittwoptions);
249:               tw.Flush();
250:           }
251:       
252:       }
253:   }

This page was automatically generated by SharpDevelop.