-
Notifications
You must be signed in to change notification settings - Fork 0
/
EmitDemo.cs
110 lines (100 loc) · 4.55 KB
/
EmitDemo.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
using LibraryProject;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace UnitTests
{
public sealed class EmitDemo
{
#region Private helpers
private static IEnumerable<string> GetReferencedAssembliesRecursively(Assembly assembly)
{
var assemblies = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var reference in assembly.GetReferencedAssemblies())
{
var referencedAssembly = Assembly.Load(reference.FullName);
assemblies.Add(referencedAssembly.Location);
assemblies.UnionWith(GetReferencedAssembliesRecursively(referencedAssembly));
}
return assemblies;
}
private static bool MethodDoesMatch(MethodInfo method)
{
var parameters = method.GetParameters();
return parameters.Length == 2 && parameters[0].ParameterType == typeof(double);
}
#endregion Private helpers
private static object CalculateSum(double a, double b)
{
const string code = @"Option strict off
Imports System
Imports Microsoft.VisualBasic
Imports LibraryProject
Namespace RoslynCore
Public Class Helper
Inherits CustomType
Function Sum(d1 As Double, d2 As Double) As Double
Return d1+d2
End Function
End Class
End Namespace";
var tree = VisualBasicSyntaxTree.ParseText(code, VisualBasicParseOptions.Default);
var binDirectory = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName;
var vbAssembly = typeof(Conversions).Assembly;
var vb = MetadataReference.CreateFromFile(vbAssembly.Location);
var fileName = "myLib";
var compilation = VisualBasicCompilation.Create(fileName)
.WithOptions(new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.AddReferences(MetadataReference.CreateFromFile(typeof(CustomType).Assembly.Location))
.AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location))
.AddReferences(vb)
.AddReferences(GetReferencedAssembliesRecursively(vbAssembly).Select(a => MetadataReference.CreateFromFile(a)))
.AddSyntaxTrees(tree);
var newpath = Path.Combine(Path.GetTempPath(), $"MyLibrary_{DateTime.Now:yyMMdd}");
Directory.CreateDirectory(newpath);
var path = Path.Combine(newpath, "MyLibrary.dll");
var compilationResult = compilation.Emit(path);
if (compilationResult.Success)
{
// below code works since our reference to LibraryProject.dll is already loaded in thi ALC
/* var nunitCustomAssemblyLoadContext = AssemblyLoadContext.All.Single(c => c.ToString().Contains("NUnit.Engine.Internal.CustomAssemblyLoadContext"));
var asm = nunitCustomAssemblyLoadContext.LoadFromAssemblyPath(path);*/
// this doesn't
var asm = Assembly.LoadFrom(path);
var type = asm.GetType("RoslynCore.Helper");
if (type == null)
throw new Exception("Type 'RoslynCore.Helper' could not be found");
var methods = type.GetMethods();
try
{
var methodInfo = methods.Where(m => StringComparer.OrdinalIgnoreCase.Equals("Sum", m.Name)).Single(m => MethodDoesMatch(m));
if (methodInfo == null)
throw new Exception($"Method 'Sum' could not be found in type {type.FullName}");
var result = methodInfo.Invoke(null, new object[] { a, b });
Console.WriteLine($"Sum is {result}");
return result;
}
catch (Exception e)
{
throw e;
}
}
foreach (var codeIssue in compilationResult.Diagnostics)
Console.WriteLine($"ID: {codeIssue.Id}, Message: {codeIssue.GetMessage()}, Location: {codeIssue.Location.GetLineSpan()}, Severity: {codeIssue.Severity}");
return null;
}
[Test]
public void Test_EmiCompilation()
{
var result = CalculateSum(1, 2);
Assert.IsNotNull(result);
Assert.AreEqual(3, (double)result);
}
}
}