.net项目的二次开发解决方案

公司原来项目的二次开发方式主要使用SQL,基本上也能满足客户的要求,优点是使用简单,只要熟悉SQL语句就可以操作,缺点是受限制太多,需要对数据库底层相当的了解,使用时容易出错,无法直接调用业务层代码等,研究了一下.net的动态编译,感觉用它来做二次开发效果应该不错的。
首先我们先做个demo来解释一下动态编译,下面这段代码的意思就是先组织一个源码字符串,然后编译执行。

 

ContractedBlock.gif ExpandedBlockStart.gif 动态编译简单代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.CodeDom.Compiler;
using Microsoft.CSharp;

namespace ConsoleApplication6
{
    
class Program
    {
        
//C#代码提供者
        private static CodeDomProvider comp = new CSharpCodeProvider();
        
//用于调用编译器的参数
        private static CompilerParameters cp = new CompilerParameters();
        
private static MethodInfo mi;
        
static void Main(string[] args)
        {
            StringBuilder codeBuilder 
= new StringBuilder();
            codeBuilder.AppendLine(
"using System;");
            codeBuilder.AppendLine(
"public class MyClass");
            codeBuilder.AppendLine(
"{");
            codeBuilder.AppendLine(
"public  void hello()");
            codeBuilder.AppendLine(
"{");
            codeBuilder.AppendLine(
"Console.WriteLine( \"hello\");");
            codeBuilder.AppendLine(
"}");
            codeBuilder.AppendLine(
"}");
            
//加入需要引用的程序集
            cp.ReferencedAssemblies.Add("System.dll"); 
            CompilerResults cr 
= comp.CompileAssemblyFromSource(cp, codeBuilder.ToString());
            
//如果有编译错误
            if (cr.Errors.HasErrors)
            {
                
foreach (CompilerError item in cr.Errors)
                {
                    Console.WriteLine(item.ToString()); 
                }
            }
            
else
            {
                Assembly a 
= cr.CompiledAssembly;   //获取已编译的程序集
                Type t = a.GetType("MyClass");      //利用反射获得类型
                object mode = a.CreateInstance("MyClass");
                mi 
= t.GetMethod("hello", BindingFlags.Instance | BindingFlags.Public);
                mi.Invoke(mode, 
new object[0]);     //执行方法
            }
        }
    }
}

 

了解了上面这段代码,我们基本对动态编译的概念清楚了,但是如果在项目中这样使用的话,我们要自己去控制源代码的全部文档内容,如果大规模应用的话会非常的麻烦,需要重复编写命名空间构造,类构造,函数构造等,如果我们还想看到一个格式良好的源码,我们还必须自己控制格式。现在我们来介绍一种源码构造方式来解决这些问题,请看如下代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 动态编译简单代码改进
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.CodeDom;
using System.IO;

namespace ConsoleApplication6
{
    
class Program
    {

        
static void Main(string[] args)
        {
            Console.WriteLine(GenerateCode(
"Hello","Hello","\t\t\treturn \"hello\";"));
        }
        
public static CodeCompileUnit CreateExecutionClass(string typeNamespace,
            
string typeName,string scriptBody)
        {
            
// 创建CodeCompileUnit以包含代码
            CodeCompileUnit ccu = new CodeCompileUnit(); 
            
// 分配需要的命名空间 
            CodeNamespace cns = new CodeNamespace(typeNamespace);
            cns.Imports.Add(
new CodeNamespaceImport("System"));
            ccu.Namespaces.Add(cns); 
            
// 创建新的类声明
            CodeTypeDeclaration parentClass = new CodeTypeDeclaration(typeName);
            cns.Types.Add(parentClass); 
            
// 创建获得一个参数并返回一个字符串的Hello方法
            CodeMemberMethod method = new CodeMemberMethod();
            method.Name 
= "Hello";
            method.Attributes 
= MemberAttributes.Public;
            CodeParameterDeclarationExpression arg 
= new CodeParameterDeclarationExpression(typeof(string), "inputMessage");
            method.Parameters.Add(arg);
            method.ReturnType 
= new CodeTypeReference(typeof(string)); 
            
// 添加方法实体需要的代码
            CodeSnippetStatement methodBody = new CodeSnippetStatement(scriptBody);
            method.Statements.Add(methodBody);
            parentClass.Members.Add(method); 
            
return ccu;
        }
        
public static string GenerateCode(string typeNamespace,
            
string typeName,string scriptBody)
        {
            
// 调用我们前面的方法创建CodeCompileUnit
            CodeCompileUnit ccu = CreateExecutionClass(typeNamespace,
            typeName, scriptBody); CSharpCodeProvider provider 
= new CSharpCodeProvider();
            CodeGeneratorOptions options 
= new CodeGeneratorOptions();
            options.BlankLinesBetweenMembers 
= false;
            options.IndentString 
= "\t";//指定缩进字符
            options.BracingStyle = "C";//大括号换行
            StringWriter sw = new StringWriter();
            
try
            {
                provider.GenerateCodeFromCompileUnit(ccu, sw, options);
                sw.Flush();
            }
            
finally
            {
                sw.Close();
            } 
            
return sw.GetStringBuilder().ToString();
        }

    }
}

 

执行结果如下:


大家了解了动态编译之后,我们这里介绍一个稍微复杂一点的应用:
需求:我们先预定义一个执行流程,而具体执行代码可以在我们项目部署之后再编写。比如说工资的计算在不同应用中算法会有很大的不同。
我们首先定义一个数据库中的数据结构:

 

然后将这个表拖入到dbml(生成的dbml文件请下载源码)文件中,现在我们就开始编写相应的代码吧:
首先我们先来处理函数的参数,如果我们只是将参数列表的字符串存入数据库中的话,我们还要根据格式序列化和反序列化这个参数,所以我们使用

xml存入sqlserver2005中,格式如下

ContractedBlock.gif ExpandedBlockStart.gif 参数格式
<Parameters>
  
<Parameter>
    
<Type>System.String</Type>
    
<ParameterName>inputMessage</ParameterName>
  
</Parameter>
  
<Parameter>
    
<Type>System.Int32</Type>
    
<ParameterName>inputInt</ParameterName>
  
</Parameter>
</Parameters>

为了方便起见我们在这里定义一个FunctionScript的分布类来处理参数问题

 

ContractedBlock.gif ExpandedBlockStart.gif 参数处理
namespace Phenix.DynamicCompiler
{
    
public partial class FunctionScript
    {
        
/// <summary>
        
/// 返回参数列表
        
/// </summary>
        
/// <returns></returns>
        public List<CodeParameterDeclarationExpression> GetParameterList()
        {
            List
<CodeParameterDeclarationExpression> parameterList = new List<CodeParameterDeclarationExpression>();
            
if (this.Parameters!=null)
            {
                var x 
= from n in this.Parameters.Elements("Parameter")
                        select n;
                
foreach (var item in x)
                {
                    parameterList.Add(
new CodeParameterDeclarationExpression(
                        Type.GetType((
string)item.Element("Type")),
                        (
string)item.Element("ParameterName")));

                }
                
            }
           
            
return parameterList;
        }
    }
}

 

然后我们需要一个代码构造类,用于根据情况构造代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码构造类
namespace Phenix.DynamicCompiler
{
    
public class CodeBuilder
    {
        StringCollection importNameSpace;
        List
<FunctionScript> functionScriptList;
        
string typeNamespace;
        
string className;

        
/// <summary>
        
/// 
        
/// </summary>
        
/// <param name="importNameSpace">导入命名空间</param>
        
/// <param name="className">类名</param>
        
/// <param name="functionInfoList">函数列表</param>
        public CodeBuilder(StringCollection importNameSpace,string typeNamespace,string className,
            List
<FunctionScript> functionScriptList)
        {
            
if (functionScriptList == null || functionScriptList.Count==0)
            {
                
throw new Exception("函数列表不能为空");
            }
            
this.importNameSpace = importNameSpace;
            
this.typeNamespace = typeNamespace;
            
this.className = className;
            
this.functionScriptList = functionScriptList;
            
if (functionScriptList.GroupBy(c => c.ClassName).Count() > 1)
            {
                
throw new Exception("这些函数不属于一个类");
            }

        }
        
public CodeBuilder(string typeNamespace,string className,
            List
<FunctionScript> functionScriptList):thisnull,typeNamespace,className,functionScriptList)
        {

        }
        
public CodeBuilder(List<FunctionScript> functionScriptList):
            
this(functionScriptList.Count==0?null:functionScriptList[0].ClassNameSpace,
            functionScriptList.Count 
== 0 ? null : functionScriptList[0].ClassName,
            functionScriptList)
        {
        }
        
private  CodeCompileUnit CreateExecutionClass()
        {
            
// 创建CodeCompileUnit以包含代码
            CodeCompileUnit ccu = new CodeCompileUnit(); // 分配需要的命名空间 
            CodeNamespace cns = new CodeNamespace(typeNamespace);
            cns.Imports.Add(
new CodeNamespaceImport("System"));
            ccu.Namespaces.Add(cns); 
// 创建新的类声明
            CodeTypeDeclaration codeClass = new CodeTypeDeclaration(className);
            cns.Types.Add(codeClass); 
// 在命名空间下加入类
            foreach (var functionScript in functionScriptList)
            {
                CodeMemberMethod method 
= new CodeMemberMethod();
                method.Name 
= functionScript.FunctionName;
                
//方法的访问标识符为public static
                method.Attributes = MemberAttributes.Static | MemberAttributes.Public;
                
foreach (var parameter in functionScript.GetParameterList())
                {
                    method.Parameters.Add(parameter);
                }

                
if (functionScript.ReturnType != null)
                {
                    method.ReturnType 
= new CodeTypeReference(Type.GetType(functionScript.ReturnType)); 
  
                }
                
// 添加方法实体需要的代码
                CodeSnippetStatement methodBody = new CodeSnippetStatement(functionScript.ScriptBody);
                method.Statements.Add(methodBody);

                codeClass.Members.Add(method); 

            }
            
return ccu;
        }
        
public  string GenerateCode()
        {
            
// 调用我们前面的方法创建CodeCompileUnit
            CodeCompileUnit ccu = CreateExecutionClass();
            CSharpCodeProvider provider 
= new CSharpCodeProvider();
            CodeGeneratorOptions options 
= new CodeGeneratorOptions();
            options.BlankLinesBetweenMembers 
= false;
            options.BracingStyle 
= "C";//大括号换行
            options.IndentString = "\t";
            StringWriter sw 
= new StringWriter();
            
try
            {
                provider.GenerateCodeFromCompileUnit(ccu, sw, options);
                sw.Flush();
            }
            
finally
            {
                sw.Close();
            }
            
return sw.GetStringBuilder().ToString();
        }
    }
}

 

下面我们再编写一个用于编译的类:

 

ContractedBlock.gif ExpandedBlockStart.gif 编译类
namespace Phenix.DynamicCompiler
{
    
public class PhenixCompiler
    {
        
/// <summary>
        
/// 编译
        
/// </summary>
        
/// <param name="codeString">需要编译的代码</param>
        
/// <param name="outputAssembly">输出程序集位置</param>
        public void Compile(string codeString, string outputAssembly)
        {
            CompilerParameters compilerParams 
= new CompilerParameters();
            
///编译器选项设置
            compilerParams.CompilerOptions = "/target:library /optimize";

            compilerParams.OutputAssembly 
= outputAssembly;
            
///生成调试信息
            compilerParams.IncludeDebugInformation = false;

            
///添加相关的引用
            foreach (var item in ReferencedAssemblies)
            {
                compilerParams.ReferencedAssemblies.Add(item);
            }

            CSharpCodeProvider provider 
= new CSharpCodeProvider();

            
///编译
            CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, codeString);
            
if (results.Errors.HasErrors)
            {
                StringBuilder errors 
= new StringBuilder();
                
foreach (CompilerError item in results.Errors)
                {
                    errors.AppendLine(item.ToString());
                }
                
throw new Exception(errors.ToString());
            }
            
///创建程序集
            Assembly asm = results.CompiledAssembly;


        }
        
private StringCollection ReferencedAssemblies
        { 
getset; }
        
public PhenixCompiler(StringCollection referencedAssemblies)
        {
            ReferencedAssemblies 
= referencedAssemblies;
            ReferencedAssemblies.Add(
"mscorlib.dll");
            ReferencedAssemblies.Add(
"System.dll");
        }
        
public PhenixCompiler()
            : 
this(new StringCollection())
        { }
    }
}

 

我们再构造一个用于执行的类:

ContractedBlock.gif ExpandedBlockStart.gif 执行类
namespace DynamicCompiler
{
    
public class Executor
    {
        
string inputAssembly;
        
string instanceName;
        
string methodName;
        
public void Execute()
        {
            Assembly assembly 
= Assembly.LoadFrom(inputAssembly);
            MethodInfo mi;
            Type t 
= assembly.GetType(instanceName);
            
object mode = assembly.CreateInstance(instanceName);
            mi 
= t.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public);
            mi.Invoke(mode, 
new object[0]); 
        }
        
public Executor(string inputAssembly,string instanceName,string methodName)
        {
            
this.inputAssembly = inputAssembly;
            
this.instanceName = instanceName;
            
this.methodName = methodName;
        }
    }
}

 

主函数代码如下:

 

ContractedBlock.gif ExpandedBlockStart.gif 主程序
class Program
    {
        
const string functionIndentSpace = "\t\t\t";
        
static void Main(string[] args)
        {
            XElement f1parameter 
= new XElement("Parameters",
                
new XElement("Parameter",
                
new XElement("Type""System.String"),
                
new XElement("ParameterName""inputMessage")),
                
new XElement("Parameter",
                
new XElement("Type""System.Int32"),
                
new XElement("ParameterName""inputInt"))
                );
            
            FunctionScript f1 
= new FunctionScript() 
            { 
                ClassName 
= "MyClass"
                ClassNameSpace 
= "My"
                FunctionName 
= "hello",
                ReturnType
="System.String",
                Parameters
=f1parameter,
                ScriptBody 
= functionIndentSpace+"return \"hello\"+inputInt.ToString();" 
            };
            FunctionScript f2 
= new FunctionScript()
            {
                ClassName 
= "MyClass",
                ClassNameSpace 
= "My",
                FunctionName 
= "hello1",
                ScriptBody 
= functionIndentSpace + "Console.WriteLine(hello(\"x\",1));"
            };
            List
<FunctionScript> list=new List<FunctionScript>();
            list.Add(f1);
            list.Add(f2);
            CodeBuilder c 
= new CodeBuilder(list);
            Console.WriteLine(c.GenerateCode());
            Compiler pc 
= new Compiler();
            pc.Compile(c.GenerateCode(), 
"x.dll");

            Executor ex 
= new Executor("x.dll""My.MyClass""hello1");
            ex.Execute();

        }
    }

 

运行结果如下

这里边工作的四个对象的时序图如下:

源码下载

在项目中应用可以结合http://www.cnblogs.com/nuaalfm/archive/2008/09/08/1286640.html中的插件编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值