在运行时重新定义基类
本文关键字:定义 基类 运行时 新定义 | 更新日期: 2023-09-27 18:25:38
程序集A包含对程序集B的引用。程序集A将程序集B中的一个类Class1-子类化。程序集C也包含相同的基类Class1。作为Class1重写的不同实现和可能不同的虚拟方法也对某些东西进行了子类化。暂时假设我疯了,想在运行时交换基类实现,替换Assembly a.中引用的内容
我已调查程序集重定向失败,因为程序集B已签名,程序集C未签名。
我无法反编译代码并合并程序集,因为有太多问题需要解决,例如不所有类的定义都很容易被发现。我不能使用CSharpCodeProvider类,因为需要子类,并且需要反编译。反射。发射太复杂了,我需要反编译。
一种选择是复制子类并根据某个开关进行动态编译,在代码中添加任何引用并将结果键入为动态。子类然后生活在一个动态对象中,但由于与另一个系统的交互,我有一种可怕的感觉,它需要在编译时或至少在更早的时候可用。代码由另一个系统调用,该系统可能使用Assembly.Load在启动时或其他任意点加载重写的程序集。
使用Assembly.Load动态加载程序集会引发各种问题,你甚至可以用这种方式替换使用反射的基类吗?
有人知道可行的解决方案吗?
编辑:更多的上下文-问题是我们覆盖了一些虚拟方法,这些方法被扩展到数千个框中。几百个盒子需要一个基类的不同实现,目前必须进行两次部署才能通过应用各种脚本来解决这个问题。其目的是为所有部署提供二进制相同的dll,最好能找到一种方法,在需要时使用config切换实现,而不是在数千次安装中更改dll,这需要重新启动软件,可能会中断业务并产生支持问题。早些时候犯了一个错误,我无法更改整体架构。
解决方案是不要子类化。is-a
依赖关系根据定义是静态的,应该保持原样。您想要实现的是一个很好的候选者,可以通过interface
将接口与实现分离,并将依赖关系降级为has-a
。然后您可以使用委派模式来完成任务。
这是构造函数注入的一个快速示例,它是依赖注入的一种特殊情况。
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注入的方法:
public SetAnimal(IAnimal a)
{
this._a = a; // hot-swap the IAnimal implementation
}
现在,您可以在构建时(在运行时)设置实现,甚至可以在执行期间进行热交换。如果在所有Bobcat
实例中共享一个a
实例,则可以获得其他功能。
所有这些的重点是用动态has-a
依赖关系替换静态is-a
依赖关系,这仍然会产生行为完全相同的实例(即,具有其他类的方法)。以下是有关委派模式的更多信息。
听起来@pid的解决方案的问题是它不适用于Activator.CreateInstance
。
解决方案是在构造函数内部进行注入(如果可以调用的话)。
这不是我在完全可以控制的系统中部署的解决方案,您也可以通过用某种运行时IL
代替换Activator.CreateInstance
来优化此代码(这将带来(实际上)几千倍的性能)。
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();
}
}