1

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

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

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

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

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

找不到方法:'Int32[] [NameSpace].[Class].CallNewMethod()'。

我知道解决此问题的最佳方法可能是检查每个函数是否存在,然后使用反射调用它们。但我只是不知道为什么代码会这样。这只是未定义的行为吗?

4

2 回答 2

0

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

为此,您需要确保在函数内部进行的每个不存在的调用以及对此类函数的调用都由版本条件控制:

private int[] WrappedNewMethod()
{
  return DLL.CallNewMethod();
}

...SomeOtherMethod()
{
   int[] someVariable = (DLLIsNewFormat) ? WrappedNewMethod(): new int[5];
}
于 2013-03-22T21:28:53.460 回答
0

这发生在包含您的代码段的方法是 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()改用,正确的方法会被自动调用。

当然,我建议使用更具描述性的名称来命名您的界面,以便清楚其含义。

于 2013-03-22T21:30:10.083 回答