程序集A包含对程序集B的引用。程序集A类的一个子类 - Class1 - 在程序集B中。程序集C也包含相同的基类 - Class1。作为Class1重写的不同实现和可能不同的虚拟方法也是子类。有一分钟我们假设我很生气,并希望在运行时替换基类实现,替换程序集A中引用的内容。
我已调查assembly redirection失败,因为程序集B已签名且程序集C未签名。
我无法反编译代码并合并程序集,因为要解决的问题太多,例如 not ,所有类的定义都很容易被发现。由于需要子类化并且需要反编译,我无法使用CSharpCodeProvider类。 Reflection.Emit过于复杂,我需要反编译。
一个选项是获取子类的副本并根据某些开关进行动态编译,在代码中添加任何引用并将结果键入为动态。然后子类生活在一个动态对象中,但由于与另一个系统的交互,我有这种可怕的感觉,它需要在编译时或至少早一点可用。该代码由另一个系统调用,该系统可能在启动时或其他任意点使用Assembly.Load加载被覆盖的程序集。
使用Assembly.Load动态加载程序集引发了各种问题,你甚至可以用这种方式用反射代替基类吗?
有人知道可行的解决方案吗?
编辑: 更多上下文 - 问题是我们覆盖了一些虚拟方法,这些方法可以推广到数千个方框。几百个盒子需要不同的基类实现,目前必须完成2次部署才能解决这个问题,并应用各种脚本。目标是为所有部署提供二进制相同的dll,并且最好找到一种方法,使用config在需要时切换实现,而不是在数千次安装中更改dll,这需要重新启动软件可能会中断业务和创建支持问题。之前已经犯了一个错误,我无法改变单片架构。
答案 0 :(得分:1)
解决方案不是子类。根据定义,is-a
依赖关系是静态的,应该保持不变。您希望实现的是通过interface
将接口与实现分离并将依赖关系降级为has-a
的良好候选者。然后,您可以使用delegation pattern来完成任务。
这是constructor injection的一个简单示例,这是dependency injection的一个特例。
interface IAnimal
{
int DoSomething();
}
class Bobcat implements IAnimal
{
private IAnimal _a;
public Bobcat(IAnimal a) // inject the dependency through the constructor
{
this._a = a;
}
public int DoSomething() // implement IAnimal
{
return _a.DoSomething(); // delegate to _a
}
}
构造函数注入的优点是您可以保证IAnimal
实现。您现在可以为setter injection添加方法:
public SetAnimal(IAnimal a)
{
this._a = a; // hot-swap the IAnimal implementation
}
您现在可以在构造(运行时)上设置实现,甚至在执行期间进行热交换。如果您在所有a
个实例中共享一个Bobcat
实例,则可以获得其他功能。
所有这一切的要点是用动态is-a
依赖项替换静态has-a
依赖项,这仍然会产生行为完全相同的实例(即,具有的方法其他类)。这里有关于delegation pattern的更多信息。
答案 1 :(得分:1)
听起来你的问题是@pid的解决方案是它不能与Activator.CreateInstance
一起使用。
解决方案是在构造函数内部执行注入(如果可以调用它)。
我不会在我完全控制的系统中部署这个解决方案,您也可以通过将Activator.CreateInstance
替换为某种运行时IL
代来优化此代码(这将带来(字面上)几千倍的性能)。
public class Foo()
{
private IImplementFoo _implimentation;
public Foo()
{
var implimentationTypeName = ConfigurationManager.AppSettings["Foo"];
var implimentationType = GetType(implimentationTypeName);
_implimentation = (IImplementFoo) Activator.CreateInstance(implimentationType);
}
public void Bar()
{
_implimentation.Bar();
}
}