using Microsoft.CodeAnalysis;
using System.IO;
using System.Reflection;
namespace Sandbox;
///
/// Loads the framework assemblies from the bin/ref folder and makes
/// them available globally to every compiler.
///
[SkipHotload]
static class FrameworkReferences
{
public static CaseInsensitiveDictionary All { get; } = new();
static FrameworkReferences()
{
var assembly = Assembly.GetExecutingAssembly();
var resourceNames = assembly.GetManifestResourceNames()
.Where( name => name.EndsWith( ".dll", StringComparison.OrdinalIgnoreCase ) )
.ToArray();
var referenceFiles = new List();
foreach ( var resourceName in resourceNames )
{
using ( var stream = assembly.GetManifestResourceStream( resourceName ) )
{
var meta = MetadataReference.CreateFromStream( stream, default, default, resourceName );
All[resourceName] = meta;
}
}
}
static Assembly FindLoadedAssembly( string name )
{
var loadedAssembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault( assembly => string.Compare( assembly.GetName().Name, name, StringComparison.OrdinalIgnoreCase ) == 0 );
if ( loadedAssembly != null )
return loadedAssembly;
try
{
// .NET lazy loads assemblies so we might need to load it now...
return Assembly.Load( name );
}
catch
{
return null;
}
}
///
/// Find a framework reference by its assembly name
///
public static PortableExecutableReference FindByName( string name )
{
if ( string.IsNullOrWhiteSpace( name ) )
throw new ArgumentException( $"cannot be null or empty", nameof( name ) );
//
// Find a ref assembly
//
if ( All.TryGetValue( $"{name}.dll", out var frameworkReference ) )
{
return frameworkReference;
}
//
// Find the assembly in our list of loaded assemblies
// We should really only do this for things like Sandbox.* ?
//
var assembly = FindLoadedAssembly( name );
if ( assembly == null )
{
throw new System.Exception( $"Couldn't find {name}.dll" );
}
if ( string.IsNullOrEmpty( assembly.Location ) )
{
throw new System.Exception( $"Found assembly {name}.dll ({assembly}) - but can't find PortableExecutableReference" );
}
return MetadataReference.CreateFromFile( assembly.Location );
}
private static List LoadEmbeddedReferenceAssemblies()
{
var assembly = Assembly.GetExecutingAssembly();
var resourceNames = assembly.GetManifestResourceNames()
.Where( name => name.EndsWith( ".dll", StringComparison.OrdinalIgnoreCase ) )
.ToArray();
var tempDirectory = Path.Combine( Path.GetTempPath(), "EmbeddedRefs" );
Directory.CreateDirectory( tempDirectory );
var referenceFiles = new List();
foreach ( var resourceName in resourceNames )
{
var outputPath = Path.Combine( tempDirectory, resourceName );
using ( var resourceStream = assembly.GetManifestResourceStream( resourceName ) )
using ( var fileStream = new FileStream( outputPath, FileMode.Create, FileAccess.Write ) )
{
resourceStream.CopyTo( fileStream );
}
referenceFiles.Add( outputPath );
}
return referenceFiles;
}
}