|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Be constructive, comment your votes... IntroductionWith CodeDom, .NET has given us a flexible tool for generating source code in a variety of languages. Unfortunately, CodeDom has a major shortcoming, it is quite "verbose": Generating a little piece of code usually means writing dozens of CodeDom instructions. This article presents Refly, a smart wrapper that should dramatically simplify code generation with CodeDom. The major features of Refly are:
We will start with a comparative example on CodeDom and Refly and then, give a how-to on using Refly. Comparative example: User class generationSuppose that we want to create the following simple namespace Refly.Demo
{
public class User
{
private string name;
public User(string name)
{
this.name = name;
}
public String Name
{
get
{
return this.name;
}
}
}
}
CodeDom solutionHere comes a part of the CodeDom code to generate the above class (skip this if you know CodeDom): // creating the Refly.Demo namespace
CodeNamespace demo = new CodeNamespace("Refly.Demo");
// create the User class
CodeTypeDeclaration user = new CodeTypeDeclaration("User");
user.IsClass = true;
demo.Types.Add(user);
// add name field
CodeMemberField name = new CodeMemberField(typeof(string),"name");
user.Members.Add(name);
// add constructor
CodeConstructor cstr = new CodeConstructor();
user.Members.Add(cstr);
CodeParameterDeclarationExpression pname =
new CodeParameterDeclarationExpression(typeof(string),"name");
cstr.Parameters.Add(pname);
// this.name = name;
CodeFieldReferenceExpression thisName = new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(),
"name");
CodeAssignStatement assign = new CodeAssignStatement(
thisName,
pname
);
cstr.Statements.Add(assign);
// add property
CodeMemberProperty p = new CodeMemberProperty();
p.Type=name.Type;
p.Name = "Name";
p.HasGet = true;
p.GetStatements.Add(
new CodeMethodReturnStatement(thisName)
);
Refly solutionHere comes the Refly version of the above. Although you do not know yet Refly, you will see that it is similar in many ways to CodeDom: // creating the Refly namespace
NamespaceDeclaration demo= new NamespaceDeclaration("Refly.Demo");
// create the user class
ClassDeclaration user = demo.AddClass("User");
// add name field
FieldDeclaration name = user.AddField(typeof(string), "name");
// add constructor
ConstructorDeclaration cstr = user.AddConstructor();
// add name parameter
ParameterDeclaration pname =
cstr.Signature.AddParam(typeof(string), "name",true);
// this.name = name;
cstr.Body.AddAssign(
Expr.This.Field(name),
Expr.Arg(pname)
);
// add property
user.AddProperty(name, true, false, false);
ComparisonAt first look, the two versions do not look very different, let me point out some interesting differences:
This concludes the introductory comparison example. The full source of the example is available in the demo. Refly ArchitectureThe Refly framework is organized in the following components:
Refly acts as a wrapper around CodeDom: each class of the CodeDom namespace has its Refly counter part. When Refly is asked to generate the code, it creates the CodeDom code and lets CodeDom generate the code. Usually, importing the Generating codeThis section gives step-by-step instructions to get you code generator running. Creating a namespaceFirst of all, we need a namespace, that is an instance of NamespaceDeclaration ns = new NamespaceDeclaration("MyNs");
Classes and enums can be added to this namespace. Sub-namespaces can also be added to namespaces. Adding a classThe ClassDeclaration user = ns.AddClass("user");
You do not need to worry about the naming case, Refly will "recase" the name you provided. Now that we have an empty type, we can test the generator. Generating codeRefly provides the CodeGenerator gen = new CodeGenerator();
gen.GenerateCode("outputPath",ns);
By default, // changin output to VB
gen.Provider=CodeGenerator.VbProvider;
Adding membersBack to our user class, you can add fields, methods, etc... by using the proper methods of // add field name
FieldDeclaration name = user.AddField(typeof(string),name);
// add Check
MethodDeclaration check = user.AddMethod("Check");
...
The signature of members (when it applies) is controlled by a // adding age to the check method
ParameterDeclaration age = check.Signature.AddParam(typeof(int),"age");
Adding commentsEach declaration type has a Documentation instance that can be used to create comments: age.Doc.Summary.AddText("user age");
Building ExpressionsThe class
The Building StatementsAs for expressions, the
More complex statements like More built-in examplesThe NamespaceDeclaration ns = ...;
ClassDeclaration col = ns.AddClass(this.Name);
// set base class as CollectionBase
col.Parent = new TypeTypeDeclaration(typeof(DictionaryBase));
// default constructor
col.AddConstructor();
// add indexer
IndexerDeclaration index = col.AddIndexer(
this.ValueType
);
ParameterDeclaration pindex = index.Signature.AddParam(KeyType,"key",false);
// get body
index.Get.Return(
(Expr.This.Prop("Dictionary").Item(Expr.Arg(pindex)).Cast(this.ValueType)
)
);
// set body
index.Set.AddAssign(
Expr.This.Prop("Dictionary").Item(Expr.Arg(pindex)),
Expr.Value
);
// add method
MethodDeclaration add = col.AddMethod("Add");
ParameterDeclaration pKey = add.Signature.AddParam(this.KeyType,"key",true);
ParameterDeclaration pValue = add.Signature.AddParam(this.ValueType,"value",true);
add.Body.Add(
Expr.This.Prop("Dictionary").Method("Add").Invoke(pKey,pValue)
);
// contains method
MethodDeclaration contains = col.AddMethod("Contains");
contains.Signature.ReturnType = new TypeTypeDeclaration(typeof(bool));
ParameterDeclaration pKey = contains.Signature.AddParam(this.KeyType,"key",true);
contains.Body.Return(
Expr.This.Prop("Dictionary").Method("Contains").Invoke(pKey)
);
// remove method
MethodDeclaration remove = col.AddMethod("Remove");
ParameterDeclaration pKey = remove.Signature.AddParam(this.KeyType,"key",true);
remove.Body.Add(
Expr.This.Prop("Dictionary").Method("Remove").Invoke(pKey)
);
The last bonusRefly contains a last bonus, XsdTidy, that refactors the output of the Xsd.exe tool to nicer and easier to use classes. History
| ||||||||||||||||||||||||||||