如何根据引用的dll的文件版本执行不同的语句?

时间:2012-11-08 11:45:25

标签: c# .net

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

如您所料,如果最新的第三方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();
}

3 个答案:

答案 0 :(得分:2)

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

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

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

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

编辑:这不是您想要的,但通过这种反射,您可以找到正确的方法,也可以用于您自己的装配。

答案 1 :(得分:1)

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

所以解决方法就是这样:

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

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

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

然而,无论如何这似乎是一个黑客攻击:你需要执行你链接的DLL版本。

答案 2 :(得分: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);
        }