Laden...

Roslyn: CSharpCompilation.Emit missachtet Referenzen

Erstellt von Fabiano vor 2 Jahren Letzter Beitrag vor 2 Jahren 744 Views
F
Fabiano Themenstarter:in
27 Beiträge seit 2021
vor 2 Jahren
Roslyn: CSharpCompilation.Emit missachtet Referenzen

Hallo Leute!

Visual Studio 2019, 16.9.4
Microsoft.CodeAnalysis.CSharp 3.9.0

Ich möchte Dapper ORM-Mappings dynamisch erstellen und verwende dazu folgenden Code:


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using DFM = Dapper.FluentMap.Mapping;

namespace Fips.ORM.Dapper
{
    public class MappersCreator
    {
        private Type CreateType(Type type, string name, Dictionary<string,string> mappings)
        {
            var assemblyName = type.Assembly.FullName;
            var nspace = type.Namespace;
            var sb = new StringBuilder();
            foreach (var kv in mappings) {
                sb.Append($"            Map(m => m.{kv.Key}).ToColumn(\"{kv.Value}\");\n");
            }
            var code = $@"using Dapper.FluentMap.Mapping;

namespace {nspace}
{{
    public class {name}Mapper : EntityMap<{name}>
    {{
        public {name}Mapper()
        {{
{sb.ToString()}
        }}
    }}
}}";
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
            CSharpCompilation compilation = CSharpCompilation.Create(
                assemblyName,
                new[] { syntaxTree },
                new MetadataReference[] {
                    MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
                    MetadataReference.CreateFromFile(type.Assembly.Location),
                    MetadataReference.CreateFromFile(typeof(DFM.EntityMap<Type>).Assembly.Location),
                    MetadataReference.CreateFromFile(typeof(Expression<Type>).Assembly.Location),
                    MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
                },
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
            );
            using (var memoryStream = new MemoryStream()) {
                EmitResult result = compilation.Emit(memoryStream);
                if (result.Success) {
                    memoryStream.Seek(0, SeekOrigin.Begin);
                    Assembly assembly = Assembly.Load(memoryStream.ToArray());
                    Type ret = assembly.GetType($"{nspace}.{name}");
                    return ret;
                } else {
                    foreach (var diagnostic in result.Diagnostics) {
                        Console.WriteLine(diagnostic);
                    }
                    return null;
                }
            }
        }
    }
}

Leider kriege ich nur folgende Fehler bei compilation.Emit(memoryStream) auf Zeile 51:> Fehlermeldung:

(5,32): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,13): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,13): error CS0012: The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,30): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,13): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,13): error CS0012: The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,33): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.

Das ist mein CSPROJ-File:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Dapper" Version="2.0.78" />
    <PackageReference Include="Dapper.FluentMap" Version="2.0.0" />
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
  </ItemGroup>

  <ItemGroup>
    <Reference Include="System.Linq" />
    <Reference Include="System.Linq.Expressions" />
    <Reference Include="netstandard" />
  </ItemGroup>
</Project>

Warum werden meine Referenzenangaben auf den Zeilen 42 und 45 (scheinbar) einfach ignoriert? Oder was ist sonst der Fehler?

Liebe Grüsse,
Fabiano

T
2.219 Beiträge seit 2008
vor 2 Jahren

Klingt für mich eher nach einem Fall für ein eigenes Snippet.
Warum machst du es dir hier schwer und willst mit Roslyn was generieren lassen, was Code Snippets in VS schon erledigen können?

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

F
Fabiano Themenstarter:in
27 Beiträge seit 2021
vor 2 Jahren

Vielen Dank für deine schnelle Antwort!

Der Typ soll natürlich zur Laufzeit generiert werden, generierter Source oder gar eine Installation von VS kann ich nicht voraussetzen.
Im Prinzip hätt ich auch per System.Reflection.Emit.GetILGenerator direkt Bytecode erzeugen können, aber das ist mir zu hoch! 😉

6.911 Beiträge seit 2009
vor 2 Jahren

Hallo Fabiano,


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

</Project>

Hat mich auch schon ein paar Nerven gekostet, aber es geht (momentan) nur mit .NET Standard 2.0 als TFM.

Edit: dazu gibt es eine Issue Don't limit Source Generators to "netstandard2.0" target framework · Issue #45162 · dotnet/roslyn

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

F
Fabiano Themenstarter:in
27 Beiträge seit 2021
vor 2 Jahren

Vielen Dank für deine Antwort!

Leider hat das auch keinen Einfluss. Das CLI ist (natürlich) netcoreapp3.1, aber der ganze Rest netstandard2.0.
Könntest du dir das kurz anschauen? So wie ich mich kenne, liegt es an was ganz Blödem...🙁

Gruss,
Fabiano

6.911 Beiträge seit 2009
vor 2 Jahren

Hallo Fabiano,

die Solution kompiliert bei mir wenn ich in Fipscode.CodeGenerator.csproj diie Referenzen hinzufüge:


<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="System.CodeDom" Version="5.0.0" />
        <PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
    </ItemGroup>

</Project>

BTW: ich dachte es ist ein Roslyn Source Generator. Sind dir diese bekannt? Damit kann zur Entwurfszeit Code erstellt werden und verweidet dies zur Laufzeit -- sofern möglich.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

J
641 Beiträge seit 2007
vor 2 Jahren

Ich denke mein problem war ähnlich. Vlt. hilgft der Issue dazu weiter: https://github.com/dotnet/roslyn/issues/50612

cSharp Projekte : https://github.com/jogibear9988

F
Fabiano Themenstarter:in
27 Beiträge seit 2021
vor 2 Jahren

Hallo gfoidl

Vielen Dank für deine Unterstützung!
Es geht mir nicht um das CodeGenerator-Projekt, sondern um ORM.Test.
Die Solution kompiliert bei mir auch, aber wenn ich das ORM.Test-Projekt ausführe, kommen diese Fehler:> Fehlermeldung:

(5,32): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,13): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,13): error CS0012: The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,30): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,13): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,13): error CS0012: The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,33): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.

Klappt das bei dir?

Ich möchte wie gesagt auch keinen Source generieren, sondern fertige Typen.

Gruss,
Fabiano

F
Fabiano Themenstarter:in
27 Beiträge seit 2021
vor 2 Jahren

Hallo jogibear9988

Diese 2 Zeilen von dir haben meinen Tag gerettet! Ach was, die ganze Woche! 🙂

                MetadataReference.CreateFromFile(Assembly.Load("netstandard").Location),
                MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location)

Nochmals vielen Dank euch beiden, dass ihr euch gekümmert habt! Einen wunderschönen Abend!

Gruss,
Fabiano

F
Fabiano Themenstarter:in
27 Beiträge seit 2021
vor 2 Jahren

Ich stecke wieder fest, und zwar erhalte ich beim Compiliern der Mapper folgende Fehler (Projekt Fipscode.ORM.Test):> Fehlermeldung:

(9,49): error CS0234: The type or namespace name 'SloganMapper' does not exist in the namespace 'Fipscode.ORM.Dapper.Fipscode.Entities.Test' (are you missing an assembly reference?)
(10,13): error CS0012: The type 'User' is defined in an assembly that is not referenced. You must add a reference to assembly 'Fipscode.Entities.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

Könntet ihr euch das vielleicht nochmal ansehen? 😉
Der zu kompilierende Sourcecode wird auch ausgegeben, zum besseren Verständnis.