Hi,前段日子写了 一个动态生成对象实体类的CodeDom
    然后这两天在使用中发现,诶~怎么就只能是使用基本类型,我 想要一些复杂类型不可以吗,比如我自定义的类或者和我本地的类型进行交互。
    不熟悉的小伙伴看这里,传送门
    终于,最后
    各种摸索之下,解决问题了
    先看下原版的内容

    1. public object CreateInstance(string context, string fullNamespaceClass)
    2. => CreateInstance(() =>
    3. {
    4. #region Verify
    5. if (string.IsNullOrEmpty(context))
    6. {
    7. throw new ArgumentException("生成的代码不能为空");
    8. }
    9. if (string.IsNullOrEmpty(fullNamespaceClass))
    10. {
    11. throw new ArgumentException("命名空间和类名称不能为空");
    12. }
    13. #endregion
    14. #region 加载构建
    15. var refPaths = new[]
    16. {
    17. typeof(System.Object).GetTypeInfo().Assembly.Location,
    18. typeof(Console).GetTypeInfo().Assembly.Location,
    19. Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll")
    20. };
    21. MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray();
    22. CSharpCompilation compilation = CSharpCompilation.Create(
    23. Path.GetRandomFileName(),
    24. syntaxTrees: new[] { CSharpSyntaxTree.ParseText(context) },
    25. references: references,
    26. options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
    27. #endregion
    28. #region 创建对象
    29. using (var ms = new MemoryStream())
    30. {
    31. EmitResult result = compilation.Emit(ms);
    32. if (result.Success)
    33. {
    34. ms.Seek(0, SeekOrigin.Begin);
    35. Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
    36. //var type = assembly.GetType("CodeDOM.CodeDOMCreatedClass");
    37. return assembly.CreateInstance(fullNamespaceClass);
    38. }
    39. else
    40. {
    41. return result.Diagnostics.Where(diagnostic =>
    42. diagnostic.IsWarningAsError ||
    43. diagnostic.Severity == DiagnosticSeverity.Error);
    44. }
    45. }
    46. #endregion
    47. });

    说实话,在一开始我不知道要怎么做,网上面对于这方面的教程也还是很少。
    但是如果你理解反射和IL的运行相信不难猜出它怎么工作的,。
    于是乎,我就摸瓜一样的把问题摸到了这里

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

    经过实践得知,或者说直接一看也能看明白,这里就是加载程序集的地方。
    那么既然可以加载系统的,为什么不可以加载我自己的呢?
    说干就干

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

    很清晰了吧。
    就这样,就解决问题了。
    但是这样做不太好,毕竟每次的IO还是不小,所以,一次过后可以把地址都缓存起来,这样就好多拉~
    加载过后,在使用中不要忘记,要AddNameSpace呦~
    就写这里吧,把问题说清楚就可以了。
    ————————————————
    原文链接:https://www.cnblogs.com/SevenWang/p/15661851.html