使用codedom自动生成代码
刚刚接触自动代码生成,便小试牛刀,解决了项目中的一些问题。
问题:我们的项目分成很多层次,当增加一个方法的时候,会显得异常繁琐,但每个层次之间的调用大同小异,所以尝试使用代码生成。现在假设有Engine, EngineBase,LocalEngine, RemoteEngine,Host等几个类,其定义和关系如下:
public class EngineFacade
{
private EngineBase engine = null;
public EngineFacade(bool isLocalEngine = true)
{
if (isLocalEngine)
{
engine = new LocalEngine();
}
else
{
engine = new RemoteEngine();
}
} public bool GetCurrentStatus()
{
return true;
}
} public abstract class EngineBase
{
public abstract bool GetCurrentStatus();
} public class LocalEngine : EngineBase
{
public override bool GetCurrentStatus()
{
return true;
}
} public class RemoteEngine : EngineBase
{
private IHost host = null; public RemoteEngine()
{
host = new Host();
} public override bool GetCurrentStatus()
{
return host.GetCurerntStatus();
}
} public interface IHost
{
bool GetCurerntStatus();
} public class Host : IHost
{
public bool GetCurerntStatus()
{
return true;
}
}
层次关系定义
上诉定义的类会被SampleClient调用:
public class SampleClient
{
public void Test()
{
var engine = new EngineFacade(false);
Console.WriteLine(engine.GetCurrentStatus());
}
}
SampleClient
如果我们需要增加一个新的方法SetStatus,如何避免额外的体力劳动呢?
解决方案:使用CodeDom进行动态代码生成。
class CodeGenerator
{
private CodeCompileUnit targetUnit = new CodeCompileUnit();
private CodeTypeDeclaration targetClass = new CodeTypeDeclaration("Test");
private static readonly string targetInstance = "engineInstance"; public CodeGenerator()
{
CodeNamespace sample = new CodeNamespace("CodeDomTest");
sample.Imports.Add(new CodeNamespaceImport("System"));
targetClass.IsClass = true;
targetClass.TypeAttributes = TypeAttributes.Public;
sample.Types.Add(targetClass);
targetUnit.Namespaces.Add(sample);
} public void AddMethod(string name, Type returnType, string comments, CodeExpression codeExpression)
{
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
method.Name = name;
method.ReturnType = new CodeTypeReference(returnType);
method.Comments.Add(new CodeCommentStatement(comments));
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement();
returnStatement.Expression = codeExpression;
method.Statements.Add(returnStatement);
targetClass.Members.Add(method);
} public void AddMethod(string name, Type returnType, string comments, CodeExpression codeExpression, string paraName, Type paraType)
{
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
method.Name = name;
method.ReturnType = new CodeTypeReference(returnType);
method.Comments.Add(new CodeCommentStatement(comments));
method.Parameters.Add(new CodeParameterDeclarationExpression(paraType, paraName));
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement();
returnStatement.Expression = codeExpression;
method.Statements.Add(returnStatement);
targetClass.Members.Add(method);
} public void AddMethod(string name, Type returnType, string comments, CodeExpression codeExpression, List<CodeParameterDeclarationExpression> parameters)
{
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
method.Name = name;
method.ReturnType = new CodeTypeReference(returnType);
method.Comments.Add(new CodeCommentStatement(comments));
method.Parameters.AddRange(parameters.ToArray());
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement();
returnStatement.Expression = codeExpression;
method.Statements.Add(returnStatement);
targetClass.Members.Add(method);
} public void AddAbstractMethod(string name, Type returnType, string comments)
{
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Abstract | MemberAttributes.Public;
method.Name = name;
method.ReturnType = new CodeTypeReference(returnType);
method.Comments.Add(new CodeCommentStatement(comments));
targetClass.Members.Add(method);
} public void AddAbstractMethod(string name, Type returnType, string comments, string paraName, Type paraType)
{
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Abstract | MemberAttributes.Public;
method.Name = name;
method.ReturnType = new CodeTypeReference(returnType);
method.Parameters.Add(new CodeParameterDeclarationExpression(paraType, paraName));
method.Comments.Add(new CodeCommentStatement(comments));
targetClass.Members.Add(method);
} public void AddField(string name, Type fieldType)
{
CodeMemberField member = new CodeMemberField();
member.Attributes = MemberAttributes.Private;
member.Name = name;
member.Type = new CodeTypeReference(fieldType);
targetClass.Members.Add(member);
} public void GenerateCode()
{
CodeDomProvider provider = new CSharpCodeProvider();
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
using (StreamWriter streamWriter = new StreamWriter("SampleReactorCode.cs"))
{
provider.GenerateCodeFromCompileUnit(targetUnit, streamWriter, options);
}
} public static void Start()
{
CodeGenerator sample = new CodeGenerator();
Test(sample);
sample.GenerateCode();
} private static void Test(CodeGenerator sample)
{
var methodToAdd = "Test";
var returnType = typeof(Dictionary<string, object>);
var paraname = "key";
var paraType = typeof(string);
var parTypes = new Dictionary<string, Type>() { { "no", typeof(int) }, { paraname, paraType } }; var parameters = GenerateParameters(parTypes);
var parArguments = GenerateParametersArguments(parTypes).ToArray(); sample.AddMethod(methodToAdd, returnType, "This is for engine facade",
new CodeMethodInvokeExpression(
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), targetInstance),
methodToAdd, parArguments), parameters);
sample.AddAbstractMethod(methodToAdd, returnType, "This is for engine base", paraname, paraType);
sample.AddMethod(methodToAdd, returnType, "This is for local engine",
new CodeMethodInvokeExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "scenario"),
methodToAdd, parArguments), parameters);
sample.AddMethod(methodToAdd, returnType, "This is for remote engine",
new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(new CodeTypeReference("HostProxy")), methodToAdd,
parArguments), parameters); var dump = parArguments.ToList();
parameters.Insert(, new CodeParameterDeclarationExpression(typeof(string), "engineKey"));
dump.Insert(, new CodeArgumentReferenceExpression("engineKey"));
parArguments = dump.ToArray(); sample.AddMethod(methodToAdd, returnType, "This is for host",
new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("InstanceManager"), methodToAdd, parArguments),
parameters); dump.Insert(, new CodePrimitiveExpression(methodToAdd));
dump.Insert(, new CodeArgumentReferenceExpression("host_name"));
parArguments = dump.ToArray();
sample.AddMethod(methodToAdd, returnType, "This is for host",
new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("host"), string.Format("Invoke<{0}>", returnType.ToString())
, parArguments), parameters);
} private static List<CodeParameterDeclarationExpression> GenerateParameters(Dictionary<string, Type> parameterTypes)
{
return parameterTypes.Select(parameterType => new CodeParameterDeclarationExpression(parameterType.Value, parameterType.Key)).ToList();
}
private static List<CodeExpression> GenerateParametersArguments(Dictionary<string, Type> parameterTypes)
{
return parameterTypes.Select(parameterType => (CodeExpression)new CodeArgumentReferenceExpression(parameterType.Key)).ToList();
}
}
CodeGenerator
如何使用CodeDom,请参考动态源代码生成和编译。
使用codedom自动生成代码的更多相关文章
- mybatis generator maven插件自动生成代码
如果你正为无聊Dao代码的编写感到苦恼,如果你正为怕一个单词拼错导致Dao操作失败而感到苦恼,那么就可以考虑一些Mybatis generator这个差价,它会帮我们自动生成代码,类似于Hiberna ...
- java如何在eclipse编译时自动生成代码
用eclipse写java代码,自动编译时,如何能够触发一个动作,这个动作是生成本项目的代码,并且编译完成后,自动生成的代码也编译好了, java编辑器中就可以做到对新生成的代码的自动提示? 不生成代 ...
- MyBatis自动生成代码示例
在项目中使用到mybatis时,都会选择自动生成实体类,Mapper,SqlMap这三个东东. 手头上在用的又不方便,找了下网上,其实有很多文章,但有些引用外部文件时不成功,也不方便,所以重新整理了下 ...
- MyBatis使用Generator自动生成代码
MyBatis中,可以使用Generator自动生成代码,包括DAO层. MODEL层 .MAPPING SQL映射文件. 第一步: 配置好自动生成代码所需的XML配置文件,例如(generator. ...
- mybatis 自动生成代码(mybatis generator)
pom.xml 文件配置 引入 mybatis generator <properties> <mysql.connector.version>5.1.44</mysql ...
- ButterKnife的使用以及不能自动生成代码问题的解决
ButterKnife的使用以及不能自动生成代码问题的解决 转载请注明出处:http://www.cnblogs.com/zhengjunfei/p/5910497.html 最近换了个工作刚入职,又 ...
- 【MyBatis】MyBatis自动生成代码查询之爬坑记
前言 项目使用SSM框架搭建Web后台服务,前台后使用restful api,后台使用MyBatisGenerator自动生成代码,在前台使用关键字进行查询时,遇到了一些很宝贵的坑,现记录如下.为展示 ...
- mybatis-generator : 自动生成代码
[参考文章]:mybatis generator自动生成代码时 只生成了insert 而没有其他 [参考文章]:Mybatis Generator最完整配置详解 1. pom <plugin&g ...
- mybatis-generator自动生成代码插件
mybatis自动生成代码(实体类.Dao接口等)是很成熟的了,就是使用mybatis-generator插件. 它是一个开源的插件,使用maven构建最好,可以很方便的执行 插件官方简介: http ...
随机推荐
- Python3下的paramiko模块
paramiko模块是基于Python实现的SSH远程安全连接,用于SSH远程执行命令.文件传输等功能. 默认Python没有,需要手动安装:pip install paramiko SSH密码认证远 ...
- ubuntu - 14.04,如何让从托盘消失的输入法图标再次显示出来?
ubuntu14.04,我也不知道怎么搞的,突然输入法图标就从托盘上消失了,这可真太不方便了,不知道自己当前是否正在使用输入法,怎么能让输入法图标再次显示在托盘上? 解决办法:确保你的“系统设置”中有 ...
- vagrant 使用
1. 下载官方的 box 文件. 官方box列表 2. 在本地创建一个目录.如: D:\test\ 3. 运行 cmd 命令,并进入 d:\test 目录 4. 添加前面下载的 box. 添加 box ...
- 洛谷P1894 [USACO4.2]完美的牛栏The Perfect Stall
题目描述 农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术.不幸的是,由于工程问题,每个牛栏都不一样.第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在 ...
- (转)接口自动化测试之http请求实践总结
一.接口测试的基本思路 1.确定要测试接口的请求类型.接口是get请求还是post请求. 2.确定接口的参数.需要传输的参数有哪些,类型分别是什么,都有哪些要求等. 3.按照参数要求构造请求需要的参数 ...
- vim简单配置(tab,行号,自动缩进)
进入到个人目录:cd - 打开vimrc文件:vim .vimrc 在文件中添加以下内容:set shiftwidth=4 #按tab键缩进4个空格set softtabstop=4 ...
- php 中 ?? 和 empty 的 区别
left??right 操作符...当 left 为空时 返回 right ..注意 和 empty 相比 ,空字符,0,'0' 都会返回它本身,而不是 右边的..也就是 当且仅当 没有设置变量或者 ...
- js 点击页面出现烟花 心形
css :1 body{width:1000px; height:500px;} input{ margin:100px; width:250px; height: 50px } 3 .Firewor ...
- Codeforces Round #335 (Div. 2) A
A. Magic Spheres time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...
- Spring里的Ant Pattern
Spring里的Ant Pattern用于匹配URL 可以参考官网:https://docs.spring.io/spring/docs/current/javadoc-api/org/springf ...