2

我有一个引用第 3 方 dll 的 C# dll。有不同版本的 3rd 方 dll。

如您所料,如果存在最新的第 3 方 dll,我想使用新功能,否则我想执行旧功能。

我不确定如何实现这一点,但我认为首先要尝试的是一个简单的 if 语句,它决定调用哪个函数。

所以我找到了程序集,得到它的位置,从而得到它的版本信息。(我需要文件版本,因为产品版本相同)。

然后一个简单的

if (version >= 3) do x() else do y()

当我在安装了版本 2 的机器上执行代码时,我得到了一个MissingMethodException关于x(). 我以为我犯了一个愚蠢的错误,但逻辑是正确的。版本为 2,因此x();不应执行。我决定删除有问题的方法并将其替换为throw new Exception(). 不抛出异常,代码成功完成。

这是危险 - 我认为这是由于分支预测。这很危险,因为这不是我所了解的领域,因此做出假设是一件危险的事情。

所以我的问题是:

我是否以错误的方式解决这个问题 - 是否有更明显的解决方案我错过了?

或者

有没有办法禁用分支预测(如果这是原因)或以某种方式强制/标记 if 条件作为在继续之前必须执行的点。

这是正在执行的代码:

  • 在安装了版本 3 的机器上就可以了。
  • 在安装了第 2 版的机器上,我得到了一个相关MissingMethodException的方法x()
  • 我删除了x();对抛出异常的调用并取消注释 - 没有抛出异常。

相关代码:

Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(3rdPartyClass));
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);

if (fileVersionInfo.FileMajorPart >= 3)
{
    // throw new Exception("aagghh");
    x();
}
else
{
    y();
}
4

3 回答 3

2

使用反射,可以获得可用于特定 DLL 的方法列表(更具体地说:类型)。

您可以使用此方法信息来动态调用 Vlad 解决方案中指定的方法。

事实上,您可以省略版本检查,直接尝试找到预期的方法。

var methodX = assembly.GetType("sometype").GetMethod("X");
if (methodX != null)
{
    methodX.Invoke(params);
}
else
{
    assembly.GetType("sometype").GetMethod("Y").Invoke(otherParams);
}

编辑:这不完全是您想要的,但是通过这种反射,您可以找到正确的方法,也适用于您自己的程序集。

于 2012-11-08T11:52:30.550 回答
1

没有“分支预测”:运行时绑定似乎在方法执行时发生。

所以解决方法是这样的:

if (fileVersionInfo.FileMajorPart >= 3)
{
    CallX();
}
else
{
    CallY();
}

void CallX()
{
    DependentClass.X();
}

void CallY()
{
    DependentClass.Y();
}

但是,无论如何,这似乎是一个 hack:您需要使用您链接的 DLL 版本来执行。

于 2012-11-08T11:49:52.610 回答
0

这实际上是一个更准确的答案:

        Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(String));
        FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);

        ObjectHandle oh = Activator.CreateInstanceFrom("AssemblyName.dll", "namespace.class");
        object o = oh.Unwrap();
        Type to = o.GetType();

        if (fileVersionInfo.FileMajorPart >= 3)
        {
            to.InvokeMember("Method X", BindingFlags.InvokeMethod, null, o, null);
        }
        else
        {
            to.InvokeMember("Method Y", BindingFlags.InvokeMethod, null, o, null);
        }
于 2012-11-08T11:58:10.870 回答