C#运行时动态创建类后如何为新类属性赋值并实现数据填充
实现动态类属性赋值的具体方案
1. 调整动态类创建方法,返回构造完成的类型
你现有createType方法没有返回生成的类类型,首先修改方法定义,编译完成后返回对应的Type实例供后续使用:
static Type createType(string name, IDictionary<string, Type> props) { var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } }); var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "Test.Dynamic.dll", false); parameters.GenerateExecutable = false; // 增加这行,允许在内存中直接访问生成的类型 parameters.GenerateInMemory = true; var compileUnit = new CodeCompileUnit(); var ns = new CodeNamespace("Test.Dynamic"); compileUnit.Namespaces.Add(ns); ns.Imports.Add(new CodeNamespaceImport("System")); var classType = new CodeTypeDeclaration(name); classType.Attributes = MemberAttributes.Public; ns.Types.Add(classType); foreach (var prop in props) { var fieldName = "_" + prop.Key; var field = new CodeMemberField(prop.Value, fieldName); classType.Members.Add(field); var property = new CodeMemberProperty(); property.Attributes = MemberAttributes.Public | MemberAttributes.Final; property.Type = new CodeTypeReference(prop.Value); property.Name = prop.Key; property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName))); property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodePropertySetValueReferenceExpression())); classType.Members.Add(property); } var results = csc.CompileAssemblyFromDom(parameters, compileUnit); results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText)); // 编译成功后返回生成的类型 if (!results.Errors.HasErrors) { return results.CompiledAssembly.GetType($"Test.Dynamic.{name}"); } return null; }
2. 两种属性赋值实现方式
方式1:使用dynamic关键字简化操作(最接近你需要的直接赋值写法)
C#的dynamic类型可以绕过编译时类型检查,运行时直接访问动态类的属性:
// 生成动态类类型 Type blogPostType = createType("BlogPost", new Dictionary<string, Type>() { { "Title", typeof(string) }, { "Text", typeof(string) }, { "Tags", typeof(string[]) } }); // 实例化动态类,用dynamic接收 dynamic post = Activator.CreateInstance(blogPostType); // 直接赋值属性,和静态类写法几乎一致 post.Title = "Title 1"; post.Text = "测试内容"; post.Tags = new string[] { "C#", "动态类" }; // 生成实例列表 List<dynamic> postList = new List<dynamic>(); postList.Add(post); // 读取属性也可以直接写 Console.WriteLine(postList[0].Title);
方式2:纯反射赋值(不需要依赖dynamic)
如果不想用dynamic,可以通过反射的SetValue方法赋值:
object post = Activator.CreateInstance(blogPostType); // 给Title属性赋值 blogPostType.GetProperty("Title").SetValue(post, "Title 1"); // 给Text属性赋值 blogPostType.GetProperty("Text").SetValue(post, "测试内容"); // 列表用List<object>存储 List<object> postList = new List<object>(); postList.Add(post); // 读取属性 var title = blogPostType.GetProperty("Title").GetValue(postList[0]);
3. 批量填充你示例中的JSON结构数据
对应你给出的多属性数组结构,可以用如下方式批量生成实例列表:
// 你的示例数据结构,用字典模拟 var data = new Dictionary<string, Array>() { { "ID", new int[] {1,2,3} }, { "Name", new string[] {"A","B","C"} }, { "Weight", new int[] {10,20,30} } }; // 先根据字段生成动态类 var class1Type = createType("Class1", new Dictionary<string, Type>() { {"ID", typeof(int)}, {"Name", typeof(string)}, {"Weight", typeof(int)} }); List<dynamic> class1List = new List<dynamic>(); // 遍历数组长度,批量生成实例 int dataCount = data["ID"].Length; for (int i = 0; i < dataCount; i++) { dynamic item = Activator.CreateInstance(class1Type); foreach (var prop in data) { // 给对应属性赋值对应索引的数值 class1Type.GetProperty(prop.Key).SetValue(item, prop.Value.GetValue(i)); } class1List.Add(item); }
注意事项
- 动态编译生成的属性名大小写敏感,赋值时需要和定义时的名称完全一致
- 赋值时需要保证数据类型和定义的属性类型匹配,否则会触发运行时异常
- 如果你不需要把动态类持久化生成dll,
parameters.GenerateInMemory设为true就不需要生成本地文件
内容的提问来源于stack exchange,提问作者J.Alex
相关产品推荐
相关产品推荐

