所以我有生产代码,针对生产dll进行编译。他们访问系统的真实架构。
我正在使用模拟器来模拟这种架构。模拟中的所有类都被命名为相同,并且属于与生产类相同的名称空间。
人们可以使用我的模拟dll对其代码进行草稿测试。
但是,如果他们调用针对生产类编译的现有生产业务逻辑,它将加载现有的生产dll并使用真实的体系结构。
如果人们想要使用我的模拟,但是调用现有的业务逻辑,我必须使用某种注入来覆盖加载生产类的dll。
这可能吗?
举个例子:
我有一个名为Production.dll
的dll
在其中有一个类似的类。
namespace Production
{
public class A { public void Do(); }
}
现在,我有一个名为Simulation.dll
的dll具有相同的类和代码。
有人写了一个名为DoA.exe
public static class Program
{
public static Main()
{
var a = new Production.A();
a.Do();
}
}
我想让DoA.exe加载我的模拟dll,但我可能无法从其搜索路径中删除Production.dll。我怎样才能强制它使用Simulation.dll。
答案 0 :(得分:1)
我想我更了解你的问题。虽然我认为我的原始解决方案更清晰,但这就是如何做到“脏”。
假设你的类模式是这样的(简化):
// assembly: Production.dll (no dependencies)
namespace Production {
public class Test {
public void Do() {
Console.Out.WriteLine("Production");
}
}
}
// assembly: Simulation.dll (no dependencies)
namespace Production {
public class Test {
public void Do() {
Console.Out.WriteLine("Simulation");
}
}
}
// assembly: Usage.dll (dependency on Production.dll)
namespace Usage {
public class TestUsage {
public void Do() {
new Production.Test().Do();
}
}
}
最后将执行覆盖的代码:
// Console application ConsoleApplication.exe
// dependency on Production.dll, Usage.dll and Simulation.dll
namespace ConsoleApplication {
internal class AssemblyResolver : MarshalByRefObject {
static internal void Register(AppDomain domain) {
var resolver = domain.CreateInstanceFromAndUnwrap(
Assembly.GetExecutingAssembly().Location,
typeof(AssemblyResolver).FullName) as AssemblyResolver;
resolver.RegisterDomain(domain);
}
private void RegisterDomain(AppDomain domain) {
domain.AssemblyResolve += ResolveAssembly;
}
private Assembly ResolveAssembly(object sender, ResolveEventArgs args) {
var assemblyName = new AssemblyName(args.Name);
string name = assemblyName.Name;
// comment out line below and you'll load "Production" instead
if (name == "Production") {
name = "Simulation";
}
var fileNames = new[] { name + ".dll", name + ".exe" };
foreach (string fileName in fileNames) {
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
if (File.Exists(path)) {
return Assembly.Load(File.ReadAllBytes(path));
}
}
return null;
}
}
class Program {
static void Main(string[] args) {
var domain = AppDomain.CreateDomain("Doable", null, new AppDomainSetup {
DisallowApplicationBaseProbing = true
});
AssemblyResolver.Register(domain);
domain.DoCallBack(() => {
// writes out "Simulation"
new Usage.TestUsage().Do();
});
}
}
}
答案 1 :(得分:0)
我使用依赖注入来处理这样的问题:
假设你有像
这样的界面public interface IDoable {
void Do();
}
Interfaces.dll中的而且你的Production.dll与类似:
namespace Production {
internal class Doable : IDoable {
public void Do() { Console.Out.WriteLine("Production"); }
}
public static class Bootstrapper {
static void Init(IServiceLocator locator) {
locator.AddSingleton<IDoable, Doable>();
}
}
}
然后你有了像
这样的类的Simulation.dllnamespace Simulation {
internal class Doable : IDoable {
public void Do() { Console.Out.WriteLine("Simulation"); }
}
public static class Bootstrapper {
static void Init(IServiceLocator locator) {
locator.AddSingleton<IDoable, Doable>();
}
}
}
然后在您的MainAssembly中,您可以引用它们,并通过配置解析您想要使用的实现(下面的天真示例)。除了配置行之外,您不必关心IDoable
来自哪个程序集 - 您只需使用它。
public static Main()
{
Production.Bootstrapper.Init(ServiceLocator.Instance);
// or you can use
// Simulation.Bootstrapper.Init(ServiceLocator.Instance);
IDoable doable = ServiceLocator.Instance.Resolve<IDoable>();
doable.Do();
}
实用程序类(使用Enterprise Library中的Microsoft Unity容器):
public interface IServiceLocator {
void Add<TFrom, TTo>() where TTo : TFrom;
void BuildUp<T>(T instance);
void BuildUp(Type type, object instance);
void AddSingleton<TFrom, TTo>() where TTo : TFrom;
void AddSingleton<TFrom, TTo>(string name) where TTo : TFrom;
void AddSingleton(Type from, Type to, string name);
void AddInstance<T>(T instance);
T Resolve<T>();
T Resolve<T>(string name);
}
public class ServiceLocator : IServiceLocator {
private IUnityContainer m_Container = new UnityContainer();
public void Add<TFrom, TTo>() where TTo : TFrom {
m_Container.RegisterType<TFrom, TTo>();
}
public void BuildUp<T>(T instance) {
m_Container.BuildUp<T>(instance);
}
public void BuildUp(Type type, object instance) {
m_Container.BuildUp(type, instance);
}
public void AddSingleton<TFrom, TTo>() where TTo : TFrom {
m_Container.RegisterType<TFrom, TTo>(new ContainerControlledLifetimeManager());
}
public void AddSingleton<TFrom, TTo>(string name) where TTo : TFrom {
m_Container.RegisterType<TFrom, TTo>(name, new ContainerControlledLifetimeManager());
}
public void AddSingleton(Type from, Type to, string name) {
m_Container.RegisterType(from, to, name, new ContainerControlledLifetimeManager());
}
public void AddInstance<T>(T instance) {
m_Container.RegisterInstance<T>(instance);
}
public T Resolve<T>() {
return m_Container.Resolve<T>();
}
public T Resolve<T>(string name) {
return m_Container.Resolve<T>(name);
}
private static IServiceLocator s_Instance;
public static IServiceLocator Instance {
get { return s_Instance; }
}
static ServiceLocator() {
var instance = new ServiceLocator();
instance.AddInstance<IServiceLocator>(instance);
s_Instance = instance;
}
}