How to use the Roslyn script view as an assembly in other Roslyn collections

I would like to reuse the script as a dynamic assembly in another Roslyn compilation that does not use scripts, but I canโ€™t figure out how to do this for my whole life.

For example, let's say I create a script in the usual way, and then release the script as an assembly into a byte stream, using something like:

var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = script.GetCompilation().WithOptions(compilationOptions);
using (var ms = new MemoryStream())
{
    EmitResult result = compilation.Emit(ms);
    ms.Seek(0, SeekOrigin.Begin);
    assembly = Assembly.Load(ms.ToArray());
}

Now let's say that I want to transfer this assembly to another compilation without scripts as a reference. I canโ€™t just use assembly, since none of the methods MetadataReference.CreateFrom...()support transferring the actual instance assembly. As a dynamic assembly, it has no location, so I cannot use it MetadataReference.CreateFromFile().

MetadataReference.CreateFromStream() , , , , script ( , ). , , , :

System.InvalidCastException: [A]Foo cannot be cast to [B]Foo. Type A originates from 'R*19cecf20-a48e-4a31-9b65-4c0163eba857#1-0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' in a byte array. Type B originates from 'R*19cecf20-a48e-4a31-9b65-4c0163eba857#1-0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' in a byte array.

, , vs. . , , script, script.

7/29

, . https://github.com/daveaglick/ScriptingAssemblyReuse.

, , script Type , Type , , script. , -, . , , , , .

:

namespace ScriptingAssemblyReuse
{
    public class Globals
    {
        public IFactory Factory { get; set; }    
    }

    public interface IFactory
    {
        object Get();
    }

    public class Factory<T> : IFactory where T : new()
    {
        public object Get() => new T();
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            new Program().Run();
        }

        private Assembly _scriptAssembly;

        public void Run()
        {
            AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;

            // Create the script
            Script<object> script = CSharpScript.Create(@"
                public class Foo { }
                Factory = new ScriptingAssemblyReuse.Factory<Foo>();
                ", ScriptOptions.Default.WithReferences(MetadataReference.CreateFromFile(typeof(IFactory).Assembly.Location)), typeof(Globals));

            // Create a compilation and get the dynamic assembly
            CSharpCompilationOptions scriptCompilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
            Compilation scriptCompilation = script.GetCompilation().WithOptions(scriptCompilationOptions);
            byte[] scriptAssemblyBytes;
            using (MemoryStream ms = new MemoryStream())
            {
                EmitResult result = scriptCompilation.Emit(ms);
                ms.Seek(0, SeekOrigin.Begin);
                scriptAssemblyBytes = ms.ToArray();
            }
            _scriptAssembly = Assembly.Load(scriptAssemblyBytes);

            // Evaluate the script
            Globals globals = new Globals();
            script.RunAsync(globals).Wait();

            // Create the consuming compilation
            string assemblyName = Path.GetRandomFileName();
            CSharpParseOptions parseOptions = new CSharpParseOptions();
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
                public class Bar
                {
                    public void Baz(object obj)
                    {
                        Script.Foo foo = (Script.Foo)obj;  // This is the line that triggers the exception 
                    }
                }", parseOptions, assemblyName);
            CSharpCompilationOptions compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
            string assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
            CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, new[] {syntaxTree},
                new[]
                {
                    MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "mscorlib.dll")),
                    MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.dll")),
                    MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Core.dll")),
                    MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Runtime.dll"))
                }, compilationOptions);
            using (MemoryStream ms = new MemoryStream(scriptAssemblyBytes))
            {
                compilation = compilation.AddReferences(MetadataReference.CreateFromStream(ms));
            }

            // Get the consuming assembly
            Assembly assembly;
            using (MemoryStream ms = new MemoryStream())
            {
                EmitResult result = compilation.Emit(ms);
                ms.Seek(0, SeekOrigin.Begin);
                byte[] assemblyBytes = ms.ToArray();
                assembly = Assembly.Load(assemblyBytes);
            }

            // Call the consuming assembly
            Type barType = assembly.GetExportedTypes().First(t => t.Name.StartsWith("Bar", StringComparison.Ordinal));
            MethodInfo bazMethod = barType.GetMethod("Baz");
            object bar = Activator.CreateInstance(barType);
            object obj = globals.Factory.Get();
            bazMethod.Invoke(bar, new []{ obj });  // The exception bubbles up and gets thrown here
        }

        private Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
        {
            if (_scriptAssembly != null && args.Name == _scriptAssembly.FullName)
            {
                // Return the dynamically compiled script assembly if given it name
                return _scriptAssembly;
            }
            return null;
        }
    }
}
+4
1

, . :

  • script.
  • script, . , ScriptClassName Script, , API- (, Submission#0) - , .
  • , .
  • script. AppDomain .
  • . , , . , script, , Submission#0, #. , script Assembly OnAssemblyResolve.
  • Baz Submission#0+Foo Script+Foo.

- , API- Roslyn Scripting. API . SourceCodeKind Script. , , script, .. - RoslynPad, , script PDB ( ).

+1

Source: https://habr.com/ru/post/1649465/


All Articles