我们有我们分发对其他DLL外部依赖的DLL。而不是冒着丢失的DLL或具有潜在的混合和匹配的情况下,我们嵌入的DLL我们自己的DLL / EXE里面并加载它在运行时,以满足运行时链接。
问:的
A)
之间 在嵌入我们的.EXE / .DLL里面的DLL,然后加载到内存在运行时 和 在保持DLL的文件系统上的一个单独的文件,然后让系统加载我们哪种方法会消耗更多的内存和大约多少钱?
B)有没有人有比上面的更好的办法?特别是对于在详细资料#3 的下面。
的兴趣在我们的程序的详细资料:的
注册为AssemblyResolve事件时,我们知道运行code在装配之前调用的部分(如:初始化时间)
公共无效SomeInit code()
{
...
AppDomain.CurrentDomain.AssemblyResolve + =(发件人,参数)=>
{
串[] assemblyDetail = args.Name.Split(,);
变种的AssemblyName = assemblyDetail [0] +为.dll;
变种thisAssembly = Assembly.GetExecutingAssembly();
变种allResourceNames = thisAssembly.GetManifestResourceNames();
串requiredResName = allResourceNames.SingleOrDefault(一个=> a.EndsWith(的AssemblyName));
使用(VAR输入= thisAssembly.GetManifestResourceStream(requiredResName))
{
返回输入!= NULL
?的Assembly.Load(StreamToBytes(输入))
: 空值;
}
};
...
}
静态的byte [] StreamToBytes(流输入)
{
无功容量= input.CanSeek? (int)的input.Length:0;
使用(VAR输出=新的MemoryStream(容量))
{
INT读数长度;
VAR缓冲区=新的字节[4096];
做
{
读数长度= input.Read(缓冲液,0,buffer.Length);
output.Write(缓冲液,0,读数长度);
}
而(读数长度!= 0);
返回output.ToArray();
}
}
嵌入汇编。这是通过添加现有项目,以.NET项目=>挑.DLL =>确定。回去挑.dll和在性质改变建设行动,以嵌入的资源。
我们还必须添加相同的.DLL作为参考,还需要有使用ExternalNamespace;对类使用它的顶部
语句。如果没有,构建过程失败,因为它无法看到外部DLL code在编译时。因此,作为一个生成后的行动,我们必须从最后的斌删除.dll文件(而不是它的嵌入式克隆)
文件夹。
答:只要将内部组件本身不具备一定规模庞大(一些大规模的嵌入式资源,例如)应该工作的可接受的 - 这是一个有点wriggly的答案,但我没有一个更好的除衡量。我(以及类似的原因)做得非常类似的事情偶尔为之。
B:将复制本地上的参考属性( F4 ),以假
。您需要在使用ExternalNamespace;
即使这些文件是在同一个项目 - 刚刚带来的空间发挥作用
We have a DLL we distribute that has external dependencies on other DLLs. Rather than risking missing DLLs or having potential mix-and-matching situations, we embed the DLLs inside our own DLL/EXE and load it at runtime to satisfy runtime linking.
Question:
A) Between
embedding the DLL inside our .EXE/.DLL and then loading it into memory at runtime and keeping the DLL as a separate file on the file system and then having the system load it for uswhich approach consumes more memory and by approximately how much?
B) Does anyone have a better approach than the above? Especially for item #3 in the details below.
Details on our process for the interested:
Register for the AssemblyResolve event at a portion that we know runs before the code in the assembly is called (eg: init time)
public void SomeInitCode()
{
...
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string[] assemblyDetail = args.Name.Split(',');
var assemblyName= assemblyDetail[0] + ".dll";
var thisAssembly = Assembly.GetExecutingAssembly();
var allResourceNames = thisAssembly.GetManifestResourceNames();
string requiredResName = allResourceNames.SingleOrDefault(a => a.EndsWith(assemblyName));
using (var input = thisAssembly.GetManifestResourceStream(requiredResName))
{
return input != null
? Assembly.Load(StreamToBytes(input))
: null;
}
};
...
}
static byte[] StreamToBytes(Stream input)
{
var capacity = input.CanSeek ? (int)input.Length : 0;
using (var output = new MemoryStream(capacity))
{
int readLength;
var buffer = new byte[4096];
do
{
readLength = input.Read(buffer, 0, buffer.Length);
output.Write(buffer, 0, readLength);
}
while (readLength != 0);
return output.ToArray();
}
}
Embed the assembly. This is done by "Add existing item" to the .NET project => pick the .dll => ok. Go back and pick the .dll and in properties change the "Build action" to "Embedded Resource".
We still have to add the same .DLL as a reference and still need to have the using ExternalNamespace;
statements on the top of classes using it. If not, build process fails since it can't see the external DLL code at compile time. So as a post-build action, we have to delete the .DLL file (not it's embedded clone) from the final bin
folder.
解决方案
A: as long as the inner assembly doesn't itself have some huge size (some massive embedded resource, for example) it should work acceptably - that is a bit of a wriggly answer, but I don't have a better one other than "measure it". I've done very similar things occasionally (and for similar reasons).
B: set "Copy Local" on the reference properties (f4) to False
. You would need the using ExternalNamespace;
even if the files were in the same project - that just brings the namespace into play.