简体   繁体   English

即使条件为真,也可以解决条件的错误部分

[英]False section of condition resolved even when condition is true

I lately have had to change a piece of code to allow compatibility with an older version DLL. 我最近不得不更改一段代码以允许与旧版本的DLL兼容。 The DLLs have the same name and are not signed. DLL具有相同的名称,并且未签名。 The difference also is in some additional methods added to the new DLL. 区别还在于添加到新DLL中的某些其他方法。

One way to go about this which doesn't seem right to me is to reference the new DLL in the project, build and run. 解决此问题的一种方法对我来说似乎不正确,那就是在项目中引用新的DLL,然后进行构建和运行。 If you want to use the other DLL, you just replace it in the bin folder. 如果要使用其他DLL,只需将其替换在bin文件夹中即可。 You can avoid errors by just checking the existence of a method in a constructor somewhere using Reflection, and set a flag so that later on you can avoid calling the new functions if you are using the older version. 您可以通过使用Reflection仅检查某个地方的构造函数中方法的存在并设置标志来避免错误,以便以后在使用较旧版本的情况下避免调用新函数。

The strange thing to me is that the following piece of code doesn't work when using the old version: 对我来说奇怪的是,使用旧版本时,以下代码不起作用:

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

Basically what is happening is that the DLLIsNewFormat is False but for some reason I get the error: 基本上发生的是DLLIsNewFormat为False,但是由于某种原因我得到了错误:

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

I understand that the best way to go about this is to probably check if each function exists and then calling them using reflection. 我知道,执行此操作的最佳方法可能是检查每个函数是否存在,然后使用反射调用它们。 But I just don't know why the code is behaving this way. 但是我只是不知道为什么代码会以这种方式运行。 Is this just undefined behavior? 这只是未定义的行为吗?

What you want is to hide calls to non-existing methods from JIT. 您想要的是隐藏对JIT中不存在的方法的调用。

To do so you need to make sure each of non-existent calls made in inside a function and call to such function is controlled by version condition: 为此,您需要确保在函数内部进行的每个不存在的调用以及对该函数的调用都受版本条件控制:

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

...SomeOtherMethod()
{
   int[] someVariable = (DLLIsNewFormat) ? WrappedNewMethod(): new int[5];
}

This is happening at the time that the method containing your snippet is JIT-compiled. 这是在包含您的代码片段的方法是JIT编译的时候发生的。 In order for JIT-compilation to happen, the method needs to be available at the time the method is invoked. 为了进行JIT编译,该方法在调用该方法时必须可用。 Since the method is not available, the JIT-compiler throws this exception when the method containing this code is called, before the method is even executed. 由于该方法不可用,因此在调用包含此代码的方法时,甚至在该方法执行之前,JIT编译器都会引发此异常。

One way around this would be to define a new method: 解决此问题的一种方法是定义一个新方法:

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

Then call this method instead of DLL.CallNewMethod() directly. 然后直接调用此方法,而不是DLL.CallNewMethod()

A better solution would be to define an interface in an assembly that is referenced by both your "conditional DLL" and the assembly you are conditionally using this DLL from. 更好的解决方案是在一个程序集中定义一个接口,该程序集同时由“条件DLL”和您有条件使用该DLL的程序集引用。 Have a default implementation of this interface available in the main assembly, and an alternate implementation in the conditionally-used DLL. 在主程序集中有此接口的默认实现,在有条件使用的DLL中具有备用实现。

Then, at runtime, you can simply see if the DLL is available, use reflection to construct an instance of the class that implements this interface, and then substitute out a the reference to your default implementation with this one. 然后,在运行时,您可以简单地查看DLL是否可用,使用反射来构造实现此接口的类的实例,然后用该实例替换对默认实现的引用。

Example code: 示例代码:

// 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();
        }
    }
}

Then you can use DLLImplementation.Instance.CallNewMethod() instead, and the right method will be called automatically. 然后,您可以改用DLLImplementation.Instance.CallNewMethod() ,然后将自动调用正确的方法。

Of course, I would suggest naming your interface with a more descriptive name so that it's apparent what it means. 当然,我建议您使用一个更具描述性的名称来命名您的界面,以便清楚地理解其含义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM