在我目前正在从事的项目中,我们进行了大量工作来对表单进行样式设置,并使它们与业务规则更加一致。这涉及到诸如表格填充,更改标签,更改列标题等之类的事情-基本上是负载。
我被要求调查制作工具以比较原始表格和新表格的可行性,以查看发生了什么变化。我已经走了使用反射的路线-获取原始DLL并依次加载表单并比较控件(我想不出更简单的方法,因为我们的许多表单还有其他项目在运行时“注入”,因此无法对设计器文件进行比较。
在我的项目中,我创建了两个名为“ OriginalAssemblies”和“ CurrentAssemblies”的目录,并且在每个目录中都有一个依赖关系目录,其中包含与窗体相关的所有程序集。这些文件主要在原始文件和当前文件之间有所不同。
我的第一个方法基于目录读取程序集,然后将其存储在列表中-有一个用于原始,一个用于当前:
private static void LoadInAssemblies(string sourceDir, List<Assembly> assemblyList)
{
DirectoryInfo dir = new DirectoryInfo(sourceDir);
foreach (FileInfo currentFile in dir.GetFiles().Where(f => f.Name.Contains("dll")))
{
assemblyList.Add(Assembly.LoadFile(currentFile.FullName));
}
}
这似乎可以很好地工作,因为它可以加载包含表单的DLL。接下来,我有一个方法以不同的形式加载并处理它们。这会运行,但是每次都会从同一目录加载依赖项
foreach (Assembly current in originalAssemblies)
{
var items = current.GetTypes().Where(t => t.IsSubclassOf(typeof(Form)) && !t.Name.Contains("Base")).ToList();
foreach (var newForm in items)
{
Object originalForm = Activator.CreateInstance(newForm);
// get the associated assembly from the new form
Object currentForm = Activator.CreateInstance (currentAssemblies.SelectMany(a => a.GetTypes()).Where (t => t.Name == newForm.Name).First());
((Form)originalForm).ShowDialog();
((Form)currentForm).ShowDialog();
}
}
经过一番研究,我在app.config中找到了有关探测的参考,因此请按以下步骤进行设置:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="OriginalAssemblies/Dependencies"/>
</assemblyBinding>
</runtime>
现在,我意识到我可以将目录分开,并具有当前目录和原始目录,但是在这种情况下,它将无济于事,因为依赖文件夹中的DLL是相同的-只是不同的程序集版本。
我的问题是,基于上述代码,在创建对象currentForm以使用正确的目录(在本例中为CurrentAssemblies)时,有什么方法可以告诉GetType()命令?
我可以加载同一种dll的多个版本。这是我想出的:
您将需要在两个 事件上使用AssemblyResolve事件AppDomain
来自动处理项目中引用的dll文件的重定向(此处“当前” dll在“ bin”中,“原始” dll在“ bin / original”中):
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// Path for to "Current" dlls.
string newPath = Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location),
"bin", new AssemblyName(args.Name).Name + ".dll");
if (File.Exists(newPath))
return Assembly.LoadFrom(newPath);
return args.RequestingAssembly;
}
private static Assembly CurrentDomain_AssemblyResolve_Original(object sender, ResolveEventArgs args)
{
// Path for the "Original" dlls.
string newPath = Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location),
"bin", "original", new AssemblyName(args.Name).Name + ".dll");
if (File.Exists(newPath))
return Assembly.LoadFrom(newPath);
return args.RequestingAssembly;
}
重要事项请确保将代码尽快放在下面(在第一个调用的构造函数中),否则事件订阅将不会被调用!:
private static readonly AppDomain OriginalAppDomain;
// Here, "Program" is my first class constructor called on startup.
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_AssemblyResolve;
// Second app domain for old DLLs.
OriginalAppDomain = AppDomain.CreateDomain("Original DLLs", new Evidence());
OriginalAppDomain.AssemblyResolve += CurrentDomain_AssemblyResolve_Original;
OriginalAppDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_AssemblyResolve_Original;
}
现在,您可以像下面这样一次性测试两个dll:
// Runs on current AppDomain.
new SpecialForm().ShowDialog();
// Runs on OriginalAppDomain (created above).
OriginalAppDomain.DoCallBack(() => new SpecialForm().ShowDialog());
可能的改进
AssemblyResolve
也可以通过检查版本而不是目录来更改方法。因此,您将对Assembly
将要加载的内容有更多控制。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句