zoukankan      html  css  js  c++  java
  • ComdeDom生成对象Emit之引用其他成员类库

    Hi,前段日子写了 一个动态生成对象实体类的CodeDom

    然后这两天在使用中发现,诶~怎么就只能是使用基本类型,我 想要一些复杂类型不可以吗,比如我自定义的类或者和我本地的类型进行交互。

    不熟悉的小伙伴看这里,传送门

    终于,最后

    各种摸索之下,解决问题了

     先看下原版的内容

           public object CreateInstance(string context, string fullNamespaceClass)
                => CreateInstance(() =>
                {
                    #region Verify
                    if (string.IsNullOrEmpty(context))
                    {
                        throw new ArgumentException("生成的代码不能为空");
                    }
                    if (string.IsNullOrEmpty(fullNamespaceClass))
                    {
                        throw new ArgumentException("命名空间和类名称不能为空");
                    }
                    #endregion
    
                    #region 加载构建
                    var refPaths = new[]
                    {
                        typeof(System.Object).GetTypeInfo().Assembly.Location,
                        typeof(Console).GetTypeInfo().Assembly.Location,
                        Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll")
                    };
                    MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray();
    
    
                    CSharpCompilation compilation = CSharpCompilation.Create(
                        Path.GetRandomFileName(),
                        syntaxTrees: new[] { CSharpSyntaxTree.ParseText(context) },
                        references: references,
                        options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
                    #endregion
    
                    #region 创建对象
                    using (var ms = new MemoryStream())
                    {
                        EmitResult result = compilation.Emit(ms);
    
                        if (result.Success)
                        {
                            ms.Seek(0, SeekOrigin.Begin);
    
                            Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
                            //var type = assembly.GetType("CodeDOM.CodeDOMCreatedClass");
                            return assembly.CreateInstance(fullNamespaceClass);
                        }
                        else
                        {
                            return result.Diagnostics.Where(diagnostic =>
                                                        diagnostic.IsWarningAsError ||
                                                        diagnostic.Severity == DiagnosticSeverity.Error);
                        }
                    }
                    #endregion
                });

    说实话,在一开始我不知道要怎么做,网上面对于这方面的教程也还是很少。

    但是如果你理解反射和IL的运行相信不难猜出它怎么工作的,。

    于是乎,我就摸瓜一样的把问题摸到了这里

              var refPaths = new[]
                    {
                        typeof(System.Object).GetTypeInfo().Assembly.Location,
                        typeof(Console).GetTypeInfo().Assembly.Location,
                        Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll")
                    };
                    MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray();

    经过实践得知,或者说直接一看也能看明白,这里就是加载程序集的地方。

    那么既然可以加载系统的,为什么不可以加载我自己的呢?

    说干就干

             List<string> dllFullPath = new List<string>();
                    DirectoryInfo root1 = new DirectoryInfo(Directory.GetCurrentDirectory());
                    foreach (FileInfo f in root1.GetFiles())
                    {
                        if (f.Name.Contains(".dll", StringComparison.OrdinalIgnoreCase))
                        {
                            dllFullPath.Add(f.FullName);
                        }
                    }
                    dllFullPath.Add(typeof(System.Object).GetTypeInfo().Assembly.Location);
                    dllFullPath.Add(typeof(Console).GetTypeInfo().Assembly.Location);
                    dllFullPath.Add(Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll"));
                    
                    MetadataReference[] references = dllFullPath.ToArray().Select(r => MetadataReference.CreateFromFile(r)).ToArray();

    很清晰了吧。

    就这样,就解决问题了。

    但是这样做不太好,毕竟每次的IO还是不小,所以,一次过后可以把地址都缓存起来,这样就好多拉~

    加载过后,在使用中不要忘记,要AddNameSpace呦~

    就写这里吧,把问题说清楚就可以了,

  • 相关阅读:
    EC++学习笔记(五) 实现
    EC++学习笔记(三) 资源管理
    EC++学习笔记(一) 习惯c++
    EC++学习笔记(六) 继承和面向对象设计
    STL学习笔记(三) 关联容器
    STL学习笔记(一) 容器
    背包问题详解
    EC++学习笔记(二) 构造/析构/赋值
    STL学习笔记(四) 迭代器
    常用安全测试用例
  • 原文地址:https://www.cnblogs.com/SevenWang/p/15661851.html
Copyright © 2011-2022 走看看