在软件开发尤其是框架和底层开发时为了更灵活的控制代码常常需要进行一些动态的操作比如根据用户的输入等动态的调用类中的方法或者根据数据库表结构用户要求动态的生成一些类然后再动态的调用类中的方法当然使用这些方式时会对性能有一点影响具体使用过程中可以根据实际情况来定不过一般的B/S开发中主要的瓶颈还是在数据库操作和网速方面这点影响应该可以忽略的 一反射的使用 可以使用反射动态地创建类型的实例将类型绑定到现有对象或从现有对象中获取类型然后可以调用类型的方法或访问其字段和属性 需要使用的命名空间SystemReflection 反射的作用很多下面的例子主要是看一下怎么动态的调用类中的方法 例子类 class ReflTest { private string _prop; public string Prop { get { return _prop; } set { _prop = value; } } public void Write(string strText) { ConsoleWriteLine(\:\ + strText); } public void Write(string strText) { ConsoleWriteLine(\:\ + strText); } public void MyWrite(string strText) { ConsoleWriteLine(\:\ + strText); } } 这个例子中提供了三个方法和一个属性下面的代码来动态的调用它们 string strText = \abcd\; BindingFlags flags = (BindingFlagsNonPublic | BindingFlagsPublic | BindingFlagsStatic | BindingFlagsInstance | BindingFlagsDeclaredOnly); Type t = typeof(ReflTest); MethodInfo[] mi = tGetMethods(flags); Object obj = ActivatorCreateInstance(t); foreach (MethodInfo m in mi) { if (mNameStartsWith(\Write\)) { mInvoke(obj new object[] { strText }); } [Page] } MethodInfo mMy = tGetMethod(\MyWrite\); if (mMy != null) { mMyInvoke(obj new object[] { strText }); } BindingFlags用来设置要取得哪些类型的方法然后我们就可以取得这些方法来动态的调用(当然为了可以循环的调用方法在方法的命名方面可以自己指定一个规则) 二动态生成类 我们可以在程序运行过程中调用NET中提供的编译类动态的将一段string编译成一个类然后再通过反射来调用它 需要使用的命名空间SystemCodeDom SystemCodeDomCompiler MicrosoftCSharp SystemReflection 动态创建编译类的代码如下 public static Assembly NewAssembly() { //创建编译器实例 provider = new CSharpCodeProvider(); //设置编译参数 paras = new CompilerParameters(); parasGenerateExecutable = false; parasGenerateInMemory = true; //创建动态代码 StringBuilder classSource = new StringBuilder(); classSourceAppend(\public class DynamicClass \\n\); classSourceAppend(\{\\n\); //创建属性 classSourceAppend(propertyString(\aaa\)); classSourceAppend(propertyString(\bbb\)); classSourceAppend(propertyString(\ccc\)); classSourceAppend(\}\); SystemDiagnosticsDebugWriteLine(classSourceToString()); //编译代码 CompilerResults result = providerCompileAssemblyFromSource(paras classSourceToString()); //获取编译后的程序集 Assembly assembly = resultCompiledAssembly; [Page] return assembly; } private static string propertyString(string propertyName) { StringBuilder sbProperty = new StringBuilder(); sbPropertyAppend(\ private int _\ + propertyName + \ = ;\\n\); sbPropertyAppend(\ public int \ + \\ + propertyName + \\\n\); sbPropertyAppend(\ {\\n\); sbPropertyAppend(\ get{ return _\ + propertyName + \;} \\n\); sbPropertyAppend(\ set{ _\ + propertyName + \ = value; }\\n\); sbPropertyAppend(\ }\); return sbPropertyToString(); }propertyString方法就是用来拼写字符串的 整个代码比较简单主要步骤就是拼写类的字符串 调用CSharpCodeProvider类进行编译得到程序集(assembly) 接下来就可以利用之前反射的方法来动态调用这个类中的属性了 Assembly assembly = NewAssembly(); object Class = assemblyCreateInstance(\DynamicClass\); ReflectionSetProperty(Class \aaa\ ); ReflectionGetProperty(Class \aaa\); object Class = assemblyCreateInstance(\DynamicClass\); ReflectionSetProperty(Class \bbb\ ); ReflectionGetProperty(Class \bbb\); DynamicClass是我动态类的类名aaa和bbb是其中的属性 ReflectionSetProperty和ReflectionGetProperty代码如下 给属性赋值 private static void ReflectionSetProperty(object objClass string propertyName int value) { PropertyInfo[] infos = objClassGetType()GetProperties(); foreach (PropertyInfo info in infos) { if (infoName == propertyName && infoCanWrite) [Page] { infoSetValue(objClass value null); } } } 取得属性的值 private static void ReflectionGetProperty(object objClass string propertyName) { PropertyInfo[] infos = objClassGetType()GetProperties(); foreach (PropertyInfo info in infos) { if (infoName == propertyName && infoCanRead) { SystemConsoleWriteLine(infoGetValue(objClass null)); } } } |