加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

使用CodeDom动态生成类型

发布时间:2016-10-29 14:35:00 所属栏目:教程 来源:站长网
导读:.NET 3.5的时候加入了匿名类型这个特性,我们可以直接使用 new {name=abc} 来直接生成一个对象。这个特性现在应用的地方很多,比如dapper的查询参数都是用匿名对象。 其实匿名对象也不是真的没有名称,编译器在编译后自动会生成一个Type。我们看看IL就知道

.NET 3.5的时候加入了匿名类型这个特性,我们可以直接使用 new {name="abc"} 来直接生成一个对象。这个特性现在应用的地方很多,比如dapper的查询参数都是用匿名对象。
其实匿名对象也不是真的没有名称,编译器在编译后自动会生成一个Type。我们看看IL就知道了。
使用CodeDom动态生成类型
编译器会自动生成一个叫做<>f__AnonymousType0`1的类型。

动态生成类型

但是有的时候我们可能类型里面的字段都是不确定的,这个时候我们就需要去动态生成一个类型了。

  • 动态生成类型第一个想到的就是反射,但是仔细想想反射都是基于现有Type的基础上完成的,咱们现在连Type都没有,所以这条路不通。
  • 第二个dynamic,dynamic确实是个好办法,可以动态指定字段的名称,但是有的三方的库不支持比如dapper。
  • 最后CodeDom,CodeDom可以在运行时直接生成一个Type。CodeDom生成Type主要分成3步。
    比如我们要生成一个Person类:

    public class Person
    {
    public string name;
    public ing age;
    
    public Person(string name ,int age)
    {
        this.name = name;
        this.age = age;
    }
    }

    构造类型

        private string _ns = "__x";
        private string _className;
        private Dictionary<Type, string> _fieldsDictionary;
    
        private string _sourceCode;
    
        private CodeCompileUnit _targetUnit;
        private CodeTypeDeclaration _targetClass;
        public SourceCodeCreater(string className,Dictionary<Type,string> fieldsDictionary )
        {
            _fieldsDictionary = fieldsDictionary;
            _className = className;
    
            _targetUnit = new CodeCompileUnit();
            CodeNamespace ns = new CodeNamespace(_ns);
            ns.Imports.Add(new CodeNamespaceImport("System"));
            _targetClass = new CodeTypeDeclaration(className);
            _targetClass.IsClass = true;
            _targetClass.TypeAttributes =
                TypeAttributes.Public | TypeAttributes.Sealed;
            ns.Types.Add(_targetClass);
            _targetUnit.Namespaces.Add(ns);
        }
    
        public string SourceCode
        {
            get { return _sourceCode; }
        }
    
        public string TypeName
        {
            get
            {
                return string.Format("{0}.{1}", _ns, _className);
            }
        }
    
        private void AddFields()
        {
            // Declare  fields .
            foreach (var kv in _fieldsDictionary)
            {
                CodeMemberField widthValueField = new CodeMemberField();
                widthValueField.Attributes = MemberAttributes.Public;
                widthValueField.Name = kv.Value;
                widthValueField.Type = new CodeTypeReference(kv.Key);
                _targetClass.Members.Add(widthValueField);
            }
        }
    
        private void AddCtor()
        {
            // Declare constructor
            CodeConstructor constructor = new CodeConstructor();
            constructor.Attributes =
                MemberAttributes.Public | MemberAttributes.Final;
    
            // Add parameters.
            foreach (var kv in _fieldsDictionary)
            {
                constructor.Parameters.Add(new CodeParameterDeclarationExpression(
               kv.Key, kv.Value));
            }
    
            // Add field initialization logic
            foreach (var kv in _fieldsDictionary)
            {
                CodeFieldReferenceExpression reference =
              new CodeFieldReferenceExpression(
              new CodeThisReferenceExpression(), kv.Value);
                constructor.Statements.Add(new CodeAssignStatement(reference,
                    new CodeArgumentReferenceExpression(kv.Value)));
            }
    
            _targetClass.Members.Add(constructor);
        }

    我们按照手写类的结构添加字段跟构造函数。

    生成CSharp代码

        public string Create()
        {
            AddFields();
    
            AddCtor();
    
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
            CodeGeneratorOptions options = new CodeGeneratorOptions();
            options.BracingStyle = "C";
    
            using (StringWriter sourceWriter = new StringWriter())
            {
                provider.GenerateCodeFromCompileUnit(
                    _targetUnit, sourceWriter, options);
                _sourceCode = sourceWriter.ToString();
            }
            return _sourceCode;
    
        }

    生成CSharp代码

    编译

        SourceCodeCreater sourceCodeCreater =new SourceCodeCreater(className,fields);
        var sourceCode = sourceCodeCreater.Create();
    
        Console.WriteLine(sourceCode);
    
        var typeName = sourceCodeCreater.TypeName;
    
        CSharpCodeProvider p = new CSharpCodeProvider();
        CompilerParameters param = new CompilerParameters(new string[] { "System.dll" });
        CompilerResults rel = p.CompileAssemblyFromSource(param, sourceCode);
        Type t = rel.CompiledAssembly.GetType(typeName);

    编译代码获得Type

运行一下

        static void Main(string[] args)
        {

            var className = "Person";
            var fields =new Dictionary<Type,string>();
            fields.Add(typeof(string),"name");
            fields.Add(typeof(int),"age");

            SourceCodeCreater sourceCodeCreater =new SourceCodeCreater(className,fields);
            var sourceCode = sourceCodeCreater.Create();

            Console.WriteLine(sourceCode);

            var typeName = sourceCodeCreater.TypeName;

            CSharpCodeProvider p = new CSharpCodeProvider();
            CompilerParameters param = new CompilerParameters(new string[] { "System.dll" });
            CompilerResults rel = p.CompileAssemblyFromSource(param, sourceCode);
            Type t = rel.CompiledAssembly.GetType(typeName);

            Console.WriteLine(t.FullName);

            foreach (var f in t.GetFields())
            {
                Console.WriteLine("Type:{0} Name:{1}",f.FieldType,f.Name);
            }

            Console.Read();
        }

使用CodeDom动态生成类型

参考

MSDN CodeDom

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读