gpt4 book ai didi

c# - 将更多 dll 加载到代码中会导致崩溃

转载 作者:太空狗 更新时间:2023-10-29 21:53:02 27 4
gpt4 key购买 nike

我正在帮助开发的系统的一个要求是能够导入文件,我们有一组适配器来处理我们可能会遇到的不同类型的文件(csv、xml 等)。在开发的早期阶段,我们通过引用和使用命令对数据适配器进行硬编码。显然,当它上线时,我们希望这样的情况是我们可以只编写一个新的适配器并将 dll 放入一个文件夹中并运行该过程而无需重新编译代码。

为了实现这一点,我改编了 this question 中的代码.有问题的代码位于构造函数中,如下所示

string dllLocation = @"C:MyLocation\dllLocation";
DirectoryInfo dir = new DirectoryInfo(dllLocation);
var tempfiles = dir.GetFiles("*Adapter*.dll", SearchOption.AllDirectories); // This will need to be changed when we go live

foreach (var file in tempfiles)
{
Assembly tempAssembly = null;

//Before loading the assembly, check all current loaded assemblies in case already loaded
//has already been loaded as a reference to another assembly
//Loading the assembly twice can cause major issues
foreach (Assembly loadedAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
//Check the assembly is not dynamically generated as we are not interested in these
if (loadedAssembly.ManifestModule.GetType().Namespace != "System.Reflection.Emit")
{
//Get the loaded assembly filename
string loadedFilename = loadedAssembly.CodeBase.Substring(loadedAssembly.CodeBase.LastIndexOf('/') + 1);

//If the filenames match, set the assembly to the one that is already loaded
if (loadedFilename.ToUpper() == file.Name.ToUpper())
{
tempAssembly = loadedAssembly;
break;
}
}
}

//If the assembly is not aleady loaded, load it manually
if (tempAssembly == null)
{
tempAssembly = Assembly.LoadFrom(file.FullName);
}

Assembly a = tempAssembly;

稍后当方法运行时我们有这个

private IEnumerable<IUniversalDataAdapter> DataAdapters
{
get
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IUniversalDataAdapter))))
{
if (type.IsAbstract) continue; // can't create abstract classes

if (!dataAdapters.Any(y => y.GetType().Equals(type)))
{
IUniversalDataAdapter adapter = (IUniversalDataAdapter)Activator.CreateInstance(type);
dataAdapters.Add(adapter);
}
}
}
return dataAdapters;
}
}

成功加载数据适配器并允许它们按我预期的方式使用。

现在的问题是,在第一段代码中我们有一行

var tempfiles = dir.GetFiles("*Adapter*.dll", SearchOption.AllDirectories);

如果我把它改成

var tempfiles = dir.GetFiles("*.dll", SearchOption.AllDirectories);

例程在第二位代码在此例程中运行之前崩溃

private IEnumerable<IDataValidator> DataValidators
{
get
{
if (validators.Count == 0)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IDataValidator))))
{
if (!type.IsAbstract)
{
var validator = (IDataValidator)Activator.CreateInstance(type, context);
validators.Add(validator);
}
}
}
}
return validators;
}
}

编辑:添加了异常(exception)

System.Reflection.ReflectionTypeLoadException was unhandled
HResult=-2146232830
Message=Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Source=mscorlib
StackTrace:
at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
at System.Reflection.RuntimeModule.GetTypes()
at System.Reflection.Assembly.GetTypes()
at TTi.Data.Pipeline.Server.Common.DataPipeline.get_DataValidators() in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 124
at TTi.Data.Pipeline.Server.Common.DataPipeline.CheckConfiguration(DataConfiguration config) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 528
at TTi.Data.Pipeline.Server.Common.DataPipeline.ProcessDataSource(IDataSource dataSource, DataConfiguration config) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 213
at TTi.Data.Test.Program.ImportTest(String testFolders) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Test\Program.cs:line 362
at TTi.Data.Test.Program.Main(String[] args) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Test\Program.cs:line 48
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:

结束编辑:

DataValidators 肯定在 DataAdapters 例程之前运行。 DataValidators 只是主代码库中包含的一些代码,用于检查以确保导入的数据具有预期的格式。此时我们只是加载它们,以便我们可以确保所需的存在。

查看加载的程序集,两个版本的代码都按需要加载适配器,但第二个版本加载的比我预期的第一个多。

那么,为什么第二个版本的 tempfiles 会在看起来完全不相关的代码部分崩溃?如果我们添加足够多的数据适配器会导致代码崩溃吗?

最佳答案

此异常表明未找到所需的 dll,因此无法加载它。现在他正在寻找哪个 dll,为什么它没有编译失败?要回答第一个问题,您需要更深入地调查,最终您会发现您的代码正在加载一些您不使用或不需要的奇怪 dll。这可能是因为代码迭代了所有加载程序集中的所有类型。可以将一个 dll 作为引用,该 dll 公开使用您未引用的其他 dll 中的某些类型的类型。只要您不使用该类型就可以。

为了解决这个问题,让你的循环更具体。很明显,您的适配器不会在任何系统 dll 中声明,那么您为什么要重复这些?

foreach (var asm in AppDomain.CurrentDomain.GetAssemblies().Where(IsMyAssembly))
{
foreach (var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IDataValidator))))
{
//...

使用 Adapter 进行的第一次文件扫描比不使用它的更好,因为它更具体。我建议通过例如在某些配置文件中显式注册类型来使您的代码更加具体,这将完全消除 dll 扫描。

关于c# - 将更多 dll 加载到代码中会导致崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41975873/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com