使用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 ...
随机推荐
- Android proguard代码混淆
为什么要代码混淆? Android的安装文件是apk格式.APK是AndroidPackage的缩写.是由android sdk编译的工程打包生成的安装程序文件. Apk其实是zip文件,但是后缀名被 ...
- android studio中Fragment使用webview返回上一页的问题
在Fragment中使用了腾讯的X5 webview,虽然好用,但是在Fragment中传递消息困难,想要返回上一页,还得各种消息传递什么的,麻烦.可是在Fragment中又不能使用onKeyDown ...
- docker常用命令行集锦
对工作中用到的docker命令行进行一个汇总,方便以后的命令行查询,同时也为了加强记忆,会把工作中用到的命令,持续更新上 1.查看私有仓库都有哪些镜像 curl -X GET http://10.27 ...
- sql开发技巧总结-2
---恢复内容开始--- 1.如何进行行列转换 需求: 列转换成行 select a.`user_name`,sum(b.kills) from user1 a join user_kills b o ...
- select和epoll原理和区别
对于select和poll,其主要原理跟epoll不同 poll和select的共同点就是,对全部指定设备(fd)都做一次poll,当然这往往都是还没有就绪的,那就会通过回调函数把当前进程注册到设备的 ...
- mybatis组合实体查询
mybatis组合实体查询 <resultMap id="wxIndexMap" type="com.o2o.common.model.wxuntity.WxInd ...
- chkconfig命令详细介绍
命令介绍 chkconfig命令用来更新.查询.修改不同运行级上的系统服务.比如安装了httpd服务,并且把启动的脚本放在了/etc/rc.d/init.d目录下,有时候需要开机自动启动它,而有时候则 ...
- java中Runtime类和Process类的简单介绍
在java.lang包当中定义了一个Runtime类,在java中对于Runtime类的定义如下: Java code public class Runtime extends Object 每个 J ...
- hdu1028 Ignatius and the Princess III(递归、DP)
Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...
- DJ
必知必会13条 all():查询所有结果 filter(**kwargs) 过滤,取到符合条件的对象,比get方法好,找不到会返回空 get(**kwargs) 取到符合条件对象,对象有 ...