/// <summary>
/// 编译程序
/// </summary>
public static class CompileAssembly
{
/// <summary>
/// 从代码中编译出类型(.net core ++ 版本平台不支持)
/// </summary>
/// <param name="sources"></param>
/// <returns></returns>
public static List<Type> CompileAssemblyFromSource(string sources)
{
#if NET5_0
return NetCore(sources);
#endif
#if NET45
return NetFramework(sources);
#endif
}
private static List<Type> NetFramework(string sources)
{
var providerOptions = new Dictionary<string, string>();
providerOptions.Add("CompilerVersion", "v4.0");
CSharpCodeProvider compiler = new CSharpCodeProvider(providerOptions);
string output = Path.GetTempFileName();
var cp = new CompilerParameters() { GenerateInMemory = true, OutputAssembly = output };
cp.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
cp.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.dll");
cp.GenerateExecutable = false;
cp.EmbeddedResources.Clear();
cp.LinkedResources.Clear();
cp.Win32Resource = null;
cp.TreatWarningsAsErrors = false;
cp.WarningLevel = 4;
cp.TempFiles.KeepFiles = false;
var ass = compiler.CompileAssemblyFromSource(cp, sources);
if (ass.Errors.HasErrors)
{
List<string> erros = new List<string>();
for (var i = 0; i < ass.Errors.Count; i++)
{
erros.Add(ass.Errors[i].ErrorText);
}
throw new XmlSqlParseException { Errors = erros };
}
return ass.CompiledAssembly.GetTypes().Where(v => v.GetCustomAttribute<SqlAttribute>() != null).ToList();
}
private static List<Type> NetCore(string sources)
{
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sources);
string output = Path.GetTempFileName();
string assemblyName = Path.GetFileName(output);
var refPaths = new[] {
Assembly.GetExecutingAssembly().Location,
typeof(object).GetTypeInfo().Assembly.Location,
Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll"),
typeof(DynamicAttribute).GetTypeInfo().Assembly.Location,
};
MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray();
CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, syntaxTrees: new[] { syntaxTree }, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
var compilationResult = compilation.Emit(output);
if (compilationResult.Success)
{
try
{
byte[] assemblyBytes = File.ReadAllBytes(output);
var ass = Assembly.Load(assemblyBytes);
return ass.GetTypes().ToList();
}
finally
{
File.Delete(output);
}
}
var error = new StringBuilder(compilationResult.Diagnostics.Length * 1024);
foreach (var t in compilationResult.Diagnostics)
{
error.AppendLine($"{t.GetMessage()}");
}
throw new XmlSqlParseException { Errors = new List<string>() { $"所选文件编译有错误{Environment.NewLine}{error}" } };
}
}