Я пытаюсь выяснить, возможно ли при динамичной генерации блоков, для ссылки на тип в ранее динамично сгенерированном блоке.
Например:
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
CodeDomProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
CompilerResults results = provider.CompileAssemblyFromSource(parameters, @"
namespace Dynamic
{
public class A
{
}
}
");
Assembly assem = results.CompiledAssembly;
CodeDomProvider provider2 = new CSharpCodeProvider();
CompilerParameters parameters2 = new CompilerParameters();
parameters2.ReferencedAssemblies.Add(assem.FullName);
parameters2.GenerateInMemory = true;
CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters2, @"
namespace Dynamic
{
public class B : A
{
}
}
");
if (results2.Errors.HasErrors)
{
foreach (CompilerError error in results2.Errors)
{
Console.WriteLine(error.ErrorText);
}
}
else
{
Assembly assem2 = results2.CompiledAssembly;
}
Этот код печатает следование консоли: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?)
Я попробовал его много различных путей, но ничто, кажется, не работает. Я пропускаю что-то? Это даже возможно?
Править: Исправление ошибки в коде обеспечивает эту ошибку вместо этого: Metadata file 'l0livsmn, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' could not be found
EDIT2: Бит примечания стороны, но изменяющийся GenerateInMemory ко лжи и выполнение parameters2.ReferencedAssemblies.Add(assem.Location);
заставит это компилировать правильно, но я значительно предпочел бы ссылаться на блок, который находится непосредственно в памяти вместо того, чтобы произвести временные файлы.
Я думаю, что в
CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters, @"
namespace Dynamic
{
public class B : A
{
}
}
");
Вы хотите передать parameters2
, а не parameters
.
Я нашел способ сделать это, вам НЕ нужно компилировать первый в памяти, если вы этого не сделаете, он создаст dll для этой сборки в вашем temp каталоге, плюс, в вашем вызове к
ReferencedAssemblies.Add()
вы не передаете имя сборки, вы передаете путь к сборке, посмотрите на этот код, он должен работать безупречно :
CodeDomProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
CompilerResults results = provider.CompileAssemblyFromSource(parameters, @"
namespace Dynamic
{
public class A
{
}
}
");
Assembly assem = results.CompiledAssembly;
CodeDomProvider provider2 = new CSharpCodeProvider();
CompilerParameters parameters2 = new CompilerParameters();
parameters2.ReferencedAssemblies.Add(assem.Location);
parameters2.GenerateInMemory = true;
CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters2, @"
namespace Dynamic
{
public class B : A
{
}
}
");
if (results2.Errors.HasErrors)
{
foreach (CompilerError error in results2.Errors)
{
Console.WriteLine(error.ErrorText);
}
}
else
{
Assembly assem2 = results2.CompiledAssembly;
}
MSDN сообщает, что вы можете:
Ограничения на ссылки на типы
Сборки могут ссылаться на типы, определенные в другой сборке. Временная динамическая сборка может безопасно ссылаться на типы, определенные в другой временной динамической сборке, постоянной динамической сборке или статической {{1} } сборка. Однако стандартная языковая среда выполнения не позволяет постоянному динамическому модулю ссылаться на тип, определенный во временном динамическом модуле . Это , потому что, когда постоянный динамический модуль загружается после сохранения на диск, среда выполнения не может разрешить ссылки на типы, определенные в {{1} }} переходный динамический модуль.