3

I recently wrote a C# app that didn't run on some PC's. The problem was that I was using a method that was only added in the SP1 version of the 3.5 .NET framework.

When the method was called, I would get an MethodNotFound exception, like in this problem: Exception is occuring only on my machine: Method not found: WaitHandle.WaitOne(Int32)

My question: Is there a tool that will examine my code (statically?), and tell me the minimum version of the .NET framework that I need (including service packs)?

Seems like it would be handy, although I'm not sure how common this is.

2
  • 6
    Microsoft screwed up on that, they added methods to mscorlib classes but didn't change the [AssemblyVersion]. They learned that lesson and took specific countermeasures against this mistake in .NET 4. There is really nothing you can do but ensure that the proper version of .NET is deployed. With a Setup project if you can't communicate your prerequisites well enough. Easy to do. Commented Mar 24, 2012 at 23:01
  • I think another scenario where this happens to me is that I write code, but I don't realize I'm using methods that won't work when if I plan to transfer the code to another platform (XBOX or WP7). I use methods and classes that aren't portable -- but at least the compiler warns me for that. Commented Mar 25, 2012 at 2:25

2 Answers 2

1

Everything that's been written here is correct, of course, but the original question has not been answered, yet. Theoretically, you could write such a tool yourself by iterating through the code and see if you find a reference to a method that first existed in this SP1. Here's a crude example that uses Cecil to parse the assembly:

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

Obviously, this example only takes that one method into account, but it should be possible to expand on it, if you really need to. :)

Sign up to request clarification or add additional context in comments.

3 Comments

Of note: Mono does expose IEnumerables here, so you can use LINQ queries against the bits in the binary :)
@BillyONeal Definitely! I just don't have a proper IDE on this PC and didn't feel like arbitarily writing incorrect LINQ on the fly. ;)
Figured. Just always love to point out my favorite feature of Cecil :P
0

I don't know of any tools to identify the minimum version of the framework your code needs to work. However you can specify it yourself using the requiredRuntime and supportedRuntime configuration settings to declare which version of the framework your application needs or supports.

When loading the application, the CLR will then raise an error and inform the user if the installed versions are not sufficient for executing your code.

1 Comment

The point is that in this case, the core changed, but the version did not. See also Hans Passant's comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.