我有一个应用程序(让我们称之为MyApp),它动态地为类创建源代码然后编译它。当它编译源代码时,我还引用了另一个文件夹中已存在的另一个DLL(这是新创建的类的基类)。我执行以下操作来编译和输出DLL:
//Create a C# code provider
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
//Set the complier parameters
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = false;
cp.TreatWarningsAsErrors = false;
cp.WarningLevel = 3;
cp.OutputAssembly = "SomeOutputPathForDLL";
// Include referenced assemblies
cp.ReferencedAssemblies.Add("mscorlib.dll");
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.Data.dll");
cp.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
cp.ReferencedAssemblies.Add("System.Xml.dll");
cp.ReferencedAssemblies.Add("System.Xml.Linq.dll");
cp.ReferencedAssemblies.Add("MyApp.exe");
cp.ReferencedAssemblies.Add("SomeFolder\SomeAdditionalReferencedDLL.dll");
// Set the compiler options
cp.CompilerOptions = "/target:library /optimize";
CompilerResults cr = provider.CompileAssemblyFromFile(cp, "PathToSourceCodeFile");
稍后在我的应用程序中(或下次应用程序运行时)我尝试创建该类的实例。我知道新创建的类(我们称之为Blah)的DLL和基类的位置。我使用以下代码尝试创建新类的实例:
Assembly assembly = Assembly.LoadFile("PathToNewClassDLL");
Blah newBlah = assembly.CreateInstance("MyApp.BlahNamespace.Blah") as Blah;
当我像上面那样调用Assembly.CreateInstance时,我收到错误消息,说它无法创建实例。当我检查assembly.GetReferencedAssemblies()它有我的应用程序(MyApp.exe)的标准引用和引用,但它没有我最初编译类时使用的依赖基类的引用(SomeAdditionalReferencedDLL.dll)
我知道我必须以某种方式添加基类引用才能创建实例,但我不知道如何做到这一点。当我拥有程序集及其所有依赖项时,如何从程序集创建类的实例?
由于
答案 0 :(得分:3)
如果手动加载外部DLL(程序集),则不会自动加载您所引用的内容。
所以你必须创建一个AssemblyLoader。一个代码,用于检查程序集的Referenced程序集并自行加载它们。
有关驻留在计算机上奇数文件夹中的引用程序集的复杂性,而不是与编译的DLL一起,请查看AppDomain.CurrentDomain.AssemblyResolve事件。 (你使用它来欺骗.NET接受你的程序集被加载,即使它不在GAC或你编译的DLL中)
使用代码手动加载引用的DLL后,CreateInstance将起作用。
答案 1 :(得分:0)
您确定在编译时,它引用了您认为引用的DLL的实例吗?它可能正在解决除了你想到的地方之外的路径,这样在实例化你的类时,它再也找不到那个DLL了。我建议获取编译过程和类型创建的Fusion日志,以了解如何解析类型。
答案 2 :(得分:0)
我认为.Net正试图在您的bin或GAC中找到“SomeAdditionalReferencedDLL.dll”。在创建新的Blah之前,您是否尝试过为“SomeAdditionalReferencedDLL.dll”进行Assembly.Load?
答案 3 :(得分:0)
答案 4 :(得分:0)
首先,我认为你有循环依赖..你的最后一段总结了它。 您需要重新考虑您的应用程序并确定您是否正确设置了职责。
为什么是循环依赖:
要生成新的dll,需要MyApp.exe;
如果没有新的dll,则无法使用MyApp.exe。
也许发布您的目标是什么,我们可以帮助您正确构建您的应用。
如果具有适当的职责,MyApp.exe应该使新生成的程序集正常工作,不要求MyApp.exe使用新dll中的对象。
示例您应该只对新生成的程序集执行执行.....
public static void RenderTemplate(String templatepath, System.IO.Stream outstream, XElement xml, Dictionary<String, object> otherdata)
{
var templateFile = System.IO.File.ReadAllText(templatepath);
var interpreter = new Interpreter();
interpreter.ReferencedAssemblies.Add("System.Core.dll"); // linq extentions
interpreter.ReferencedAssemblies.Add("System.Xml.dll");
interpreter.ReferencedAssemblies.Add("System.Xml.Linq.dll");
interpreter.UsingReferences.Add("System.Linq");
interpreter.UsingReferences.Add("System.Xml");
interpreter.UsingReferences.Add("System.Xml.Linq");
interpreter.UsingReferences.Add("System.Collections.Generic");
interpreter.Execute(templateFile, outstream, xml, otherdata);
}
答案 5 :(得分:0)
//Constructor
static MyClass()
{
//Provoque l'événement quand .Net ne sait pas retrouver un Assembly référencé
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
/// <summary>
/// Mémorise les assembly référencés par d'autres qui ne sont pas dans le répertoire principal d'EDV
/// </summary>
static Dictionary<string, string> _AssembliesPath;
/// <summary>
/// .Net ne sait pas retrouver un Assembly référencé
/// Cherche et charge d'après les assembly référencés par d'autres qui ne sont pas dans le répertoire principal d'EDV
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
/// <returns></returns>
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (_AssembliesPath != null && _AssembliesPath.ContainsKey(args.Name))
{
Assembly lAssembly = Assembly.LoadFile(_AssembliesPath[args.Name]);
AddAssemblyReferencedAssemblies(lAssembly, System.IO.Path.GetDirectoryName(lAssembly.Location));
return lAssembly;
}
Error = string.Format("L'assembly {0} n'a pu être chargé", args.Name);
return null;
}
/// <summary>
/// Mémorise les assembly référencés par d'autres qui ne sont pas dans le répertoire principal d'EDV
/// </summary>
/// <param name="pAssembly"></param>
/// <param name="psRootPath"></param>
static void AddAssemblyReferencedAssemblies(Assembly pAssembly, string psRootPath)
{
if (_AssembliesPath == null) _AssembliesPath = new Dictionary<string, string>();
foreach (AssemblyName lRefedAss in pAssembly.GetReferencedAssemblies())
if (!_AssembliesPath.ContainsKey(lRefedAss.FullName))
{
string lsRoot = psRootPath + "\\" + lRefedAss.Name + ".";
string lsExt;
if (System.IO.File.Exists(lsRoot + (lsExt = "dll")) || System.IO.File.Exists(lsRoot + (lsExt = "exe")))
{
_AssembliesPath.Add(lRefedAss.FullName, lsRoot + lsExt);
}
}
}
//函数调用 程序集lAssembly = Assembly.LoadFile(lsExternalAssemblyPath); AddAssemblyReferencedAssemblies(lAssembly,System.IO.Path.GetDirectoryName(lsExternalAssemblyPath));