有没有用于检查最低.NET框架版本的工具?

3
我最近编写了一款 C# 应用程序,在某些电脑上无法运行。问题在于我使用的方法只在 3.5 .NET 框架 SP1 版本中添加了。
当调用该方法时,会出现 MethodNotFound 异常,就像这个问题中所示:Exception is occuring only on my machine: Method not found: WaitHandle.WaitOne(Int32) 我的问题是:有没有工具可以检查我的代码(静态地?),并告诉我需要的 .NET 框架的最低版本(包括服务包)?
似乎会很方便,尽管我不确定这有多常见。

6
微软公司在这方面搞砸了,他们给mscorlib类添加了方法,但没有改变[AssemblyVersion]。他们吸取了教训,在.NET 4中采取了具体的对策来避免这个错误。你唯一能做的就是确保正确版本的.NET被部署。如果你不能很好地传达你的先决条件,那么使用Setup项目就很容易做到。 - Hans Passant
我认为另一种情况是,当我编写代码时,我没有意识到我正在使用的方法在将代码转移到另一个平台(XBOX或WP7)时无法工作。我使用的方法和类不可移植--但至少编译器会警告我。 - jm.
2个回答

1

这里写的一切都是正确的,当然,原始问题还没有得到回答。理论上,您可以通过迭代代码并查看是否存在对在此SP1中首次存在的方法的引用来编写这样的工具。以下是一个使用Cecil解析程序集的简单示例:

namespace SampleNamespace
{
  using System;
  using Mono.Cecil;
  using Mono.Cecil.Cil;

  internal static class Program
  {
    public static void Main(string[] args)
    {
      foreach (string arg in args)
      {
        Console.WriteLine("{0}: {1}", arg, NeedsDotNet35SP1(arg));
        Console.ReadLine();
      }
    }

    private static bool NeedsDotNet35SP1(string fileName)
    {
      return NeedsDotNet35SP1(ModuleDefinition.ReadModule(fileName));
    }

    private static bool NeedsDotNet35SP1(ModuleDefinition module)
    {
      if (TargetRuntime.Net_2_0 != module.Runtime)
      {
        // I don't care about .NET 1.0, 1.1. or 4.0 for this example.
        return false;
      }

      foreach (TypeDefinition type in module.Types)
      {
        if (NeedsDotNet35SP1(type))
        {
          return true;
        }
      }

      return false;
    }

    private static bool NeedsDotNet35SP1(TypeDefinition type)
    {
      foreach (MethodDefinition method in type.Methods)
      {
        if (NeedsDotNet35SP1(method))
        {
          return true;
        }
      }

      return false;
    }

    private static bool NeedsDotNet35SP1(MethodDefinition method)
    {
      return NeedsDotNet35SP1(method.Body);
    }

    private static bool NeedsDotNet35SP1(MethodBody body)
    {
      foreach (Instruction instruction in body.Instructions)
      {
        if (NeedsDotNet35SP1(instruction))
        {
          return true;
        }
      }

      return false;
    }

    private static bool NeedsDotNet35SP1(Instruction instruction)
    {
      if (OperandType.InlineMethod != instruction.OpCode.OperandType)
      {
        return false;
      }

      return NeedsDotNet35SP1((MethodReference)instruction.Operand);
    }

    private static bool NeedsDotNet35SP1(MethodReference method)
    {
      return method.FullName.Equals(
        "System.Boolean System.Threading.WaitHandle::WaitOne(System.Int32)",
        StringComparison.OrdinalIgnoreCase);
    }
  }
}

显然,这个例子只考虑了一个方法,但如果您真的需要,可以进行扩展。 :)


值得注意的是:Mono在这里确实公开了IEnumerable,因此您可以对二进制位使用LINQ查询 :) - Billy ONeal
@BillyONeal 当然没问题! 但是,我这台电脑上没有合适的集成开发环境,并且不想随意编写错误的LINQ代码。 ;) - hangy
明白了。我总是喜欢指出 Cecil 的最爱功能 :P - Billy ONeal

0

我不知道有什么工具可以识别您的代码需要的框架的最低版本。 但是,您可以使用requiredRuntime和supportedRuntime配置设置自行指定应用程序需要或支持的框架版本。

加载应用程序时,CLR将引发错误并通知用户如果安装的版本不足以执行您的代码。


1
重点是在这种情况下,核心发生了变化,但版本没有改变。请参阅Hans Passant的评论。 - Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接