您如何添加对使用Roslyn在内存流中编译的类型的引用?

问题描述 投票:6回答:3

作为编译输入,我有一个包含以下代码的字符串:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public string EmailAddress { get; set; }
}

我有以下代码,请注意[01]处的注释。这里的目的是采用包含类的字符串(来自this.Source,并将用于汇编的代码发送到MemoryStream

var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
var assemblyName = Guid.NewGuid().ToString();
var syntaxTrees = CSharpSyntaxTree.ParseText(this.Source);

// build references up
var references = new List<MetadataReference>();
//[01] references.Add("System.dll")); 

// set up compilation
var compilation = CSharpCompilation.Create(assemblyName)
    .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
    .AddReferences(references)
    .AddSyntaxTrees(syntaxTrees);

// build the assembly
Assembly assembly;
using (var stream = new MemoryStream())
{
    // this is broked...
    EmitResult compileResult = compilation.Emit(stream);
    // [02] we get here, with diagnostic errors (check compileResult.Diagnostics)
    assembly = Assembly.Load(stream.GetBuffer());
}

[02],我得到一个BadImageFormat异常,在compileResult.Diagnostics中具有以下内容:

[0]: warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options.
[1]: (2,18): error CS0518: Predefined type 'System.Object' is not defined or imported
[2]: (4,16): error CS0518: Predefined type 'System.String' is not defined or imported
[3]: (4,40): error CS0518: Predefined type 'System.Void' is not defined or imported
[4]: (5,16): error CS0518: Predefined type 'System.String' is not defined or imported
[5]: (5,39): error CS0518: Predefined type 'System.Void' is not defined or imported
[6]: (6,16): error CS0518: Predefined type 'System.Int32' is not defined or imported
[7]: (6,31): error CS0518: Predefined type 'System.Void' is not defined or imported
[8]: (7,16): error CS0518: Predefined type 'System.String' is not defined or imported
[9]: (7,43): error CS0518: Predefined type 'System.Void' is not defined or imported
[10]: (2,18): error CS1729: 'object' does not contain a constructor that takes 0 arguments

如果在代码的开头添加using System;,则会出现以下错误:

error CS0246: The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?)

这使我相信我无法从坐着的地方访问System,这就是为什么我在该伪代码references.Add("System.dll"));中加注了。这显然是不正确的,但这是我的意图。

有关更多信息,此处的目的是动态创建所生成类型的实例,并将值分配给属性。

使引用可用于编译器的正确方法是什么?

或者,还有另一种方法来编译这样的类(从字符串输入)?

.net compilation roslyn asp.net-core
3个回答
4
投票

调用AssemblyMetadata.CreateFromFile(path) method,并传递AssemblyMetadata.CreateFromFile(path)(或其他组件)。


0
投票

您可以使用此技术来获取程序集的完整路径

typeof(object).Assembly.Location

所以您可以结束此:

var assemblyFullPath = typeof(object).Assembly.Location);

UPDATE

您可以尝试使用:

references.Add(new MetadataFileReference(typeof(object).Assembly.Location)));

0
投票

对于.net核心,您可以使用

PortableExecutableReference MetadataReference.CreateFromImage(
        ImmutableArray<byte> peImage,
        MetadataReferenceProperties properties = default(MetadataReferenceProperties),
        DocumentationProvider documentation = null,
        string filePath = null)

我这样使用它:

   public static class TrustedPlatformAssembly
   {
      public static string From( string shortDllName )
      {
         string dllString = AppContext.GetData( "TRUSTED_PLATFORM_ASSEMBLIES" ).ToString();
         var dlls = dllString.Split( ";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries );
         string dll = dlls.Single( d => d.Contains( shortDllName, StringComparison.OrdinalIgnoreCase ) );
         return dll;
      }
   }
© www.soinside.com 2019 - 2024. All rights reserved.