在运行时重新定义基类

本文关键字:定义 基类 运行时 新定义 | 更新日期: 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();
    }
}