我们可以在程序运行过程中调用.NET中提供的编译类,动态的将一段string编译成一个类,然后再通过反射来调用它
需要使用的命名空间: System.CodeDom System.CodeDom.Compiler Microsoft.CSharp System.Reflection
整个代码比较简单,主要步骤就是:1、拼写类的字符串 2、调用CSharpCodeProvider类进行编译得到程序集(assembly)
接下来就可以利用之前反射的方法来动态调用这个类中的属性了:
http://technet.microsoft.com/zh-cn/library/system.codedom.compiler.compilerparameters%28v=vs.90%29
需要使用的命名空间: System.CodeDom System.CodeDom.Compiler Microsoft.CSharp System.Reflection
动态创建、编译类的代码如下:
public static Type CreateDynamicType(string typeName)
{
//创建编译器实例。
CSharpCodeProvider provider = new CSharpCodeProvider();
//设置编译参数。
CompilerParameters paras = new CompilerParameters();
paras.GenerateExecutable = false;
paras.GenerateInMemory = true;
paras.IncludeDebugInformation = true;
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(x => !x.IsDynamic).Select(x => x.Location);
paras.ReferencedAssemblies.AddRange(assemblies.ToArray());
//创建动态代码。
StringBuilder classSource = new StringBuilder();
bool containsNamespace = false;
string newTypeName = typeName;
if (typeName.Contains("."))
{
int index = typeName.LastIndexOf(".");
newTypeName = typeName.Substring(index+1);
classSource.Append("namespace " + typeName.Substring(0, index) + " {\n");
containsNamespace = true;
}
classSource.Append(@"public class " + newTypeName + " \n");
classSource.Append("{\n");
//创建属性。
classSource.Append(CreatePropertyString("Prop1", "string"));
classSource.Append(CreatePropertyString("Prop2", "int"));
classSource.Append(CreatePropertyString("Prop3","string"));
classSource.Append("}\n");
if (containsNamespace)
{
classSource.Append("}\n");
}
//System.Diagnostics.Debug.WriteLine(classSource.ToString());
//编译代码。
CompilerResults result = provider.CompileAssemblyFromSource(paras, classSource.ToString());
if (result.Errors.HasErrors)
{
foreach (CompilerError error in result.Errors)
{
Console.WriteLine(error.Line + ":" + error.ErrorText);
}
return null;
}
//获取编译后的程序集。
Assembly assembly = result.CompiledAssembly;
return assembly.GetType(typeName);
}
private static string CreatePropertyString(string propertyName, string typeName)
{
StringBuilder sbProperty = new StringBuilder();
sbProperty.Append(string.Format(" private {0} _{1} ;\n", typeName, propertyName));
sbProperty.Append(string.Format(" public {0} {1} \n", typeName, propertyName));
sbProperty.Append(" {\n");
sbProperty.Append(" get{ return _"+propertyName+";}\n");
sbProperty.Append(" set{_"+propertyName+" = value; }\n");
sbProperty.Append(" }\n");
return sbProperty.ToString();
}
private static void ReflectionSetProperty(object objClass, string propertyName, object value)
{
PropertyInfo[] infos = objClass.GetType().GetProperties();
foreach (PropertyInfo info in infos)
{
if (info.Name == propertyName && info.CanWrite)
{
info.SetValue(objClass, value, null);
}
}
}
private static object ReflectionGetProperty(object objClass, string propertyName)
{
PropertyInfo[] infos = objClass.GetType().GetProperties();
foreach (PropertyInfo info in infos)
{
if (info.Name == propertyName && info.CanRead)
{
object obj = info.GetValue(objClass, null);
return obj;
}
}
return null;
}
整个代码比较简单,主要步骤就是:1、拼写类的字符串 2、调用CSharpCodeProvider类进行编译得到程序集(assembly)
接下来就可以利用之前反射的方法来动态调用这个类中的属性了:
Type type = CreateDynamicType("ConsoleApp.DynamicClass");
object Class1 = Activator.CreateInstance(type);
ReflectionSetProperty(Class1, "Prop1", "10");
object aaa = ReflectionGetProperty(Class1, "Prop1");
Console.WriteLine(aaa);
object Class2 = Activator.CreateInstance(type);
ReflectionSetProperty(Class1, "Prop2", 20);
object bbb = ReflectionGetProperty(Class1, "Prop2");
Console.WriteLine(bbb);
有关CompilerParameters的介绍跟多参见
object Class1 = Activator.CreateInstance(type);
ReflectionSetProperty(Class1, "Prop1", "10");
object aaa = ReflectionGetProperty(Class1, "Prop1");
Console.WriteLine(aaa);
object Class2 = Activator.CreateInstance(type);
ReflectionSetProperty(Class1, "Prop2", 20);
object bbb = ReflectionGetProperty(Class1, "Prop2");
Console.WriteLine(bbb);
http://technet.microsoft.com/zh-cn/library/system.codedom.compiler.compilerparameters%28v=vs.90%29