刚刚接触自动代码生成,便小试牛刀,解决了项目中的一些问题。

问题:我们的项目分成很多层次,当增加一个方法的时候,会显得异常繁琐,但每个层次之间的调用大同小异,所以尝试使用代码生成。现在假设有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自动生成代码的更多相关文章

  1. mybatis generator maven插件自动生成代码

    如果你正为无聊Dao代码的编写感到苦恼,如果你正为怕一个单词拼错导致Dao操作失败而感到苦恼,那么就可以考虑一些Mybatis generator这个差价,它会帮我们自动生成代码,类似于Hiberna ...

  2. java如何在eclipse编译时自动生成代码

    用eclipse写java代码,自动编译时,如何能够触发一个动作,这个动作是生成本项目的代码,并且编译完成后,自动生成的代码也编译好了, java编辑器中就可以做到对新生成的代码的自动提示? 不生成代 ...

  3. MyBatis自动生成代码示例

    在项目中使用到mybatis时,都会选择自动生成实体类,Mapper,SqlMap这三个东东. 手头上在用的又不方便,找了下网上,其实有很多文章,但有些引用外部文件时不成功,也不方便,所以重新整理了下 ...

  4. MyBatis使用Generator自动生成代码

    MyBatis中,可以使用Generator自动生成代码,包括DAO层. MODEL层 .MAPPING SQL映射文件. 第一步: 配置好自动生成代码所需的XML配置文件,例如(generator. ...

  5. mybatis 自动生成代码(mybatis generator)

    pom.xml 文件配置 引入 mybatis generator <properties> <mysql.connector.version>5.1.44</mysql ...

  6. ButterKnife的使用以及不能自动生成代码问题的解决

    ButterKnife的使用以及不能自动生成代码问题的解决 转载请注明出处:http://www.cnblogs.com/zhengjunfei/p/5910497.html 最近换了个工作刚入职,又 ...

  7. 【MyBatis】MyBatis自动生成代码查询之爬坑记

    前言 项目使用SSM框架搭建Web后台服务,前台后使用restful api,后台使用MyBatisGenerator自动生成代码,在前台使用关键字进行查询时,遇到了一些很宝贵的坑,现记录如下.为展示 ...

  8. mybatis-generator : 自动生成代码

    [参考文章]:mybatis generator自动生成代码时 只生成了insert 而没有其他 [参考文章]:Mybatis Generator最完整配置详解 1. pom <plugin&g ...

  9. mybatis-generator自动生成代码插件

    mybatis自动生成代码(实体类.Dao接口等)是很成熟的了,就是使用mybatis-generator插件. 它是一个开源的插件,使用maven构建最好,可以很方便的执行 插件官方简介: http ...

随机推荐

  1. Mac下配置MAMP Pro+PHPStorm

    一.配置MAMP Pro Hosts 下载地址:http://xclient.info/s/mamp-pro.html 在Hosts页签下,如图所示位置选择你工程目录 二.配置PHPStorm 1.点 ...

  2. 对Dapper的一点改造

    微软推出的ORM, EF在我开发的项目中给我的感觉一直都是慢.优点是高度封装的底层.便于开发. Dapper在多篇性能比较的网站中.都是名列前三.缺点是手写SQL,不便于开发.   如果能结合EF的优 ...

  3. CentOS6.5上Zabbix3.0的RPM安装【二】-汉化

    六.汉化 zabbix实际是有中文语言的,我们可以通过修改web端源文件来开启中文语言.首先点击zabbix监控页面右上角管理员头像进入“用户基本资料设置页面“. 选择中文语言. 点击“Update” ...

  4. yum(Fedora和RedHat以及SUSE中的Shell前端软件包管理器)命令详解

    yum官方网站:http://yum.baseurl.org/ Fedora对于yum的介绍:http://fedoraproject.org/wiki/Yum yum(全称为 Yellow dog ...

  5. winform按钮文字换行

    用button的Bounds属性 btn.Bounds = new Rectangle(new Point(5 + i * 143, 25), new Size(100, 60));

  6. 【谁知道C#字段为什么用属性封装?】

    源地址:https://zhidao.baidu.com/question/1174413218458798139.html 我们知道,类成员包括变量和方法.如果希望其他类能够访问成员变量的值,就必须 ...

  7. uoj#450. 【集训队作业2018】复读机(单位根反演)

    题面 传送门 题解 我的生成函数和单位根反演的芝士都一塌糊涂啊-- \(d=1\),答案就是\(k^n\)(因为这里\(k\)个复读机互不相同,就是说有标号) \(d=2\),我们考虑复读机的生成函数 ...

  8. Python学习之路--1.0 Python概述及基本数据类型

    Python是一门解释性语言,弱类型语言 python程序的两种编写方式: 1.进入cmd控制台,输入python进入编辑模式,即可直接编写python程序 2.在.朋友文件中编写python代码,通 ...

  9. Qt 学习之路 2(26):反走样

    Qt 学习之路 2(26):反走样 豆子 2012年11月12日 Qt 学习之路 2 9条评论 我们在光栅图形显示器上绘制非水平.非垂直的直线或多边形边界时,或多或少会呈现锯齿状外观.这是因为直线和多 ...

  10. csv HTTP简单表服务器

    HTTP Simple Table Server Download Performance testing with JMeter can be done with several JMeter in ...