[小技巧] C# 使用 CodeDOM 动态创建类文件

本文介绍了如何使用C#的CodeDOM来动态创建类文件,并展示了生成的类代码示例。文章还提供了创建类的源代码,以及调用方式和测试代码,最终实现了动态编程的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态创建类文件

动态创建类文件后,就可以使用上一篇文章[小技巧]C# .net 动态编程 (1)中的动态编译生成动态的对象了。这样就方便多了。

知识点

CodeDOM

效果

通过类动态生成cs类

就是写文件操作,为什么这样做呢,这让我联想到了WCF引用自动生成代码的东西。
以下是自动生成的类

//------------------------------------------------------------------------------
// <auto-generated>
//     此代码由工具生成。
//     运行时版本:4.0.30319.42000
//
//     对此文件的更改可能会导致不正确的行为,并且如果
//     重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------

namespace Test
{
    using System;
    using System.Collections.Generic;
    
    
    public partial class Test
    {
        
        ///  <summary>
        /// A
        ///  </summary>
        private int A;
        
        ///  <summary>
        /// b
        ///  </summary>
        private string b;
        
        ///  <summary>
        /// bList
        ///  </summary>
        private System.Collections.Generic.List<string> bList;
        
        ///  <summary>
        /// B
        ///  </summary>
        public virtual string B
        {
            get
            {
                return this.b;
            }
            set
            {
                this.b = value;
            }
        }
        
        ///  <summary>
        /// BList
        ///  </summary>
        public virtual System.Collections.Generic.List<string> BList
        {
            get
            {
                return this.bList;
            }
            set
            {
                this.bList = value;
            }
        }
    }
}

调用方式

   ClassCreator creator = new ClassCreator();
            creator.AddFields("A", typeof(int));
            creator.AddFields("A", typeof(string));
            creator.AddProperties("B", typeof(string));
            creator.AddProperties("BList", typeof(List<string>));
            if (creator.GenerateCode("Test", "Test"))
                Console.WriteLine("Success");
            else
                Console.WriteLine("Failed");

创建类的源代码

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace 动态编程
{
    public class ClassCreator
    {
        /// <summary>
        /// Define the compile unit to use for code generation.
        /// </summary>
        private CodeCompileUnit targetUnit;

        /// <summary>
        /// The only class in the compile unit. This class contains 2 fields,
        /// 3 properties, a constructor, an entry point, and 1 simple method.
        /// </summary>
        private CodeTypeDeclaration targetClass;

        private List<string> namespaceNames;
        /// <summary>
        /// 字段
        /// </summary>
        private List<CodeMemberField> codeMemberFields;
        /// <summary>
        /// 属性
        /// </summary>
        private List<CodeMemberProperty> codeMemberPropertys;


        /// <summary>
        /// Define the class.
        /// </summary>
        public ClassCreator()
        {
            namespaceNames = new List<string>();
            codeMemberFields = new List<CodeMemberField>();
            codeMemberPropertys = new List<CodeMemberProperty>();
        }

        /// <summary>
        /// 添加字段
        /// </summary>
        /// <param name="fileName">字段名称</param>
        /// <param name="type">字段类型</param>
        /// <param name="visitLevel">访问级别 默认是private</param>
        /// <param name="comments">字段描述信息</param>
        public void AddFields(string fileName, Type type, MemberAttributes visitLevel = MemberAttributes.Private, string comments = null)
        {
            if (codeMemberFields.Exists(t => t.Name == fileName)) return;
            CodeMemberField field = new CodeMemberField();
            field.Attributes = visitLevel;
            field.Name = fileName;
            field.Type = new CodeTypeReference(type);
            field.Comments.Add(new CodeCommentStatement(
               " <summary>", true));
            field.Comments.Add(new CodeCommentStatement(
              comments ?? fileName, true));
            field.Comments.Add(new CodeCommentStatement(
              " </summary>", true));
            codeMemberFields.Add(field);
            AddNamespance(type);
        }


        /// <summary>
        /// 添加属性
        /// </summary>
        /// <param name="propertyName">属性名称</param>
        /// <param name="type">属性类型</param>
        /// <param name="comments">属性描述信息</param>
        public void AddProperties(string propertyName, Type type, bool hasGet = true, bool hasSet = true, string comments = null)
        {
            if (codeMemberPropertys.Exists(t => t.Name == propertyName)) return;
            CodeMemberProperty property = new CodeMemberProperty();
            property.Attributes = MemberAttributes.Public;
            property.Name = propertyName;
            property.HasGet = hasGet;
            property.HasSet = hasSet;
            property.Type = new CodeTypeReference(type);
            property.Comments.Add(new CodeCommentStatement(
             " <summary>", true));
            property.Comments.Add(new CodeCommentStatement(
              comments ?? propertyName, true));
            property.Comments.Add(new CodeCommentStatement(
              " </summary>", true));
            var fileName = (propertyName[0]).ToString().ToLower() + propertyName.Substring(1);
            if (!codeMemberFields.Exists(t => t.Name == fileName))
                AddFields(fileName, type, MemberAttributes.Private, comments);

            property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fileName)));
            CodeFieldReferenceExpression reference = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fileName);
            property.SetStatements.Add(new CodeAssignStatement(reference, new CodeArgumentReferenceExpression("value")));
            codeMemberPropertys.Add(property);
            AddNamespance(type);
        }

        private void AddNamespance(Type type)
        {
            if (namespaceNames.IndexOf(type.Namespace) == -1)
                namespaceNames.Add(type.Namespace);
        }

        /// <summary>
        /// 生成代码
        /// </summary>
        /// <param name="namespaceName">命名空间</param>
        /// <param name="className">类型</param>
        /// <param name="visitLevel">访问级别,默认是Public</param>
        /// <param name="filePath">文件完整路径,默认是程序所在目录,和类名同名</param>
        /// <returns>true | false</returns>
        public bool GenerateCode(string namespaceName, string className, TypeAttributes visitLevel = TypeAttributes.Public, string filePath = null)
        {
            try
            {
                targetUnit = new CodeCompileUnit();
                CodeNamespace newClass = new CodeNamespace(namespaceName);
                targetClass = new CodeTypeDeclaration(className);
                targetClass.IsClass = true;
                targetClass.TypeAttributes = visitLevel;
                targetClass.IsPartial = true;
                newClass.Types.Add(targetClass);
                targetUnit.Namespaces.Add(newClass);

                namespaceNames.ForEach(item =>
                {
                    newClass.Imports.Add(new CodeNamespaceImport(item));
                });

                codeMemberFields.ForEach(item =>
                {
                    targetClass.Members.Add(item);
                });

                codeMemberPropertys.ForEach(item =>
                {
                    targetClass.Members.Add(item);
                });

                CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
                CodeGeneratorOptions options = new CodeGeneratorOptions();
                options.BracingStyle = "C";
                using (StreamWriter sourceWriter = new StreamWriter(filePath ?? $"{className}.cs"))
                {
                    provider.GenerateCodeFromCompileUnit(
                        targetUnit, sourceWriter, options);
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }

        }
    }
}

测试代码

先添加刚刚生成的文件到项目,然后再main函数中添加如下代码

  Test.Test t = new Test.Test() {  B="aaaa"};
  Console.WriteLine(t.B);

运行效果

在这里插入图片描述

总结

可以生成代码了,再根据上一篇的内容动态编译,一定可以实现动态编程的。

注:下一篇试下以下结合使用

https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/how-to-create-a-class-using-codedom

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值