即使条件为真,也解决条件的False部分

本文关键字:条件 解决 False 部分 | 更新日期: 2023-09-27 18:05:17

我最近不得不更改一段代码以允许与旧版本的DLL兼容。dll具有相同的名称并且没有签名。不同之处还在于新DLL中添加了一些额外的方法。

有一种方法可以解决这个问题,这对我来说似乎不正确,那就是在项目中引用新的DLL,构建并运行。如果您想使用其他DLL,只需将其替换到bin文件夹中。您可以通过使用反射检查构造函数中是否存在方法来避免错误,并设置一个标志,以便以后如果您使用旧版本,可以避免调用新函数。

对我来说奇怪的是,当使用旧版本时,以下代码段不起作用:

int[] someVariable = (DLLIsNewFormat) ? DLL.CallNewMethod() : new int[5];

基本上发生的事情是DLLIsNewFormat是False但由于某种原因,我得到了错误:

方法未找到:'Int32[] [NameSpace].[Class]. callnewmethod ()'.

我明白最好的方法是检查每个函数是否存在,然后使用反射调用它们。但我不知道为什么代码是这样的。这只是未定义行为吗?

即使条件为真,也解决条件的False部分

这是在包含代码片段的方法被jit编译时发生的。为了进行jit编译,该方法需要在调用该方法时可用。由于该方法不可用,因此在调用包含此代码的方法时,甚至在执行该方法之前,jit编译器都会抛出此异常。

解决这个问题的一种方法是定义一个新方法:
int[] HideCall()
{
    return DLL.CallNewMethod();
}

则直接调用此方法而不是DLL.CallNewMethod()

一个更好的解决方案是在程序集中定义一个接口,该接口由您的"条件DLL"和您有条件地使用此DLL的程序集引用。在主程序集中提供此接口的默认实现,并在有条件使用的DLL中提供备用实现。

然后,在运行时,您可以简单地查看DLL是否可用,使用反射来构造实现此接口的类的实例,然后用此实例替换对默认实现的引用。

示例代码:

// Interface, in an assembly visible to both of the other assemblies.
public interface IDLLInterface
{
    int[] CallNewMethod();
}
// Implementation in the main program.
class DefaultDLLImplementation : IDLLInterface
{
    public int[] CallNewMethod()
    {
        return new int[5];
    }
}
static class DLLImplementation
{
    public readonly IDLLInterface Instance;
    static DLLImplementation()
    {
        // Pseudo-code
        if (DllIsAvailable) {
            Instance = ConstructInstanceFromDllUsingReflection();
        } else {
            Instance = new DefaultDLLImplementation();
        }
    }
}

那么您可以使用DLLImplementation.Instance.CallNewMethod()代替,并且将自动调用正确的方法。

当然,我建议用一个更具描述性的名字来命名你的界面,这样它的意思就很明显了。

您需要的是在JIT中隐藏对不存在的方法的调用。

要做到这一点,您需要确保在函数内部进行的每个不存在的调用和对该函数的调用都由版本条件控制:
private int[] WrappedNewMethod()
{
  return DLL.CallNewMethod();
}
...SomeOtherMethod()
{
   int[] someVariable = (DLLIsNewFormat) ? WrappedNewMethod(): new int[5];
}