4

I'd like to cause compiler errors local to methods that need to be changed once I make the transition to .NET Framework 4.0. See below:

Oops, while this is just an example, this code totally does not work, something I just realized. (a corrected version is available at the end, if you ever need this kind of functionality)

// ASP.NET 3.5 does not contain a global accessor for routing data
// this workaround will be used until we transition to .NET 4.0

// this field still exists in .NET 4.0, however, it is never used
// GetRouteData will always return null after the transition to .NET 4.0

static object _requestDataKey = typeof(UrlRoutingModule)
    .GetField("_requestDataKey", BindingFlags.NonPublic | BindingFlags.Instance)
    .GetValue(null)
    ;

public static RouteData GetRouteData(this HttpContext context)
{
    if (context != null)
    {
        return context.Items[_requestDataKey] as RouteData;
    }
    // .NET 4.0 equivalent
    //if ((context != null) && (context.Request != null))
    //{
    //    return context.Request.RequestContext.RouteData;
    //}
    return null;
}

Does anyone know of a trick that results in a compiler error once the transition is made?

This code actually does what the original version intended. This code is also not specific to the 3.5 version of the runtime, however, there are simpler yet ways of getting at the route data in 4.0.

if (context != null)
{
    var routeData = context.Items["RouteData"] as RouteData;
    if (routeData == null
        && !context.Items.Contains("RouteData"))
    {
        context.Items["RouteData"] = routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(context));
    }
    return routeData;
}
John Leidegren
  • 59,920
  • 20
  • 131
  • 152

5 Answers5

4

I think there is no built-in preprocessor symbol, but you could roll your own:

public static RouteData GetRouteData(this HttpContext context) 
{
    if (context != null)     
    {         
       return context.Items[_requestDataKey] as RouteData;     
    }
#if NET_4
#error Review code for .NET
#endif

    // .NET 4.0 equivalent     
    //if ((context != null) && (context.Request != null))     
    //{     
    //    return context.Request.RequestContext.RouteData;     
    //}     
    return null; 
} 

Then, when you compile your projects for .NET 4, add the "NET_4" symbol to the compiler's symbols (via VS.NET project properties or directly in the .csproj file).

Of course, this requires that you know the places of interest (i.e. via code review). I think there is no way to have it happen automatically.

Christian.K
  • 47,778
  • 10
  • 99
  • 143
  • Oh, an error preprocessor directive, nice, I didn't know there was one. This will work, all I need to do is to define the symbol when compiling against the new framework and these errors should surface. Thanks @Christian.K – John Leidegren Jan 10 '11 at 12:34
2

Use Environment.Version.

Gets a Version object that describes the major, minor, build, and revision numbers of the common language runtime.

You can use this in your method to print out errors, throw exceptions etc...

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • +1, I like this solution as it allows the code to be backward-compatible. However, his questions states he requires something at compile time? – Moo-Juice Jan 10 '11 at 10:24
  • @Moo-Juice - I know what he asked for, but think this is a better option. If this is put in the initialization of the application, it can be made to not run at all. – Oded Jan 10 '11 at 10:27
  • Actually I don't require it to be compile-time, but if there's an option of doing it through static verification, why not? The issues I have with run-time checking is that it's just that, run-time checking. You have to run it, to find out. That necessitates a lot of testing, which isn't bad in anyway, but not something that I have a lot of time to get down to, on top of everything else. – John Leidegren Jan 13 '11 at 17:39
1

You could use the Obsolete attribute on the method in question

[Obsolete("Upgrade Method to .NET 4.0", true)]

The boolean on the end specifies that the compiler should generate an error if this method is used. Therefore in your cause, you could pass false here, and have it generate a warning so that your program still functions but provides feedback that you need to upgrade the method.

Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
1

You could use conditional compilation to achieve the result, but not the method, that you're after. If you see this answer it describes setting conditional values. Define one for targeting .NET 3.5, and wrap the old code in that. Wrap the new code in an IFNDEF or something similar. I haven't used conditional compilation myself, but that's the angle I first thought of.

Community
  • 1
  • 1
Josh Smeaton
  • 47,939
  • 24
  • 129
  • 164
1

Well, runtime errors are easy to create but compile-time errors a bit trickier. First, do you want to detect a new .NET Framework version or a new compiler version? I do not know of a way to detect difference in runtime version at compile-time.

There is, however, a way to trigger an error when compiling with the Visual Studio 2010 compiler (as opposed to the 2008 version). Let's take a look at the C# 2010 breaking changes list at http://msdn.microsoft.com/en-us/library/ee855831(VS.100).aspx.

The difference in null-coalescing operator behavior with regard to uninitialized local variables seems like a good candidate for this.

#pragma warning disable 0219
bool? i;
bool? j;
// TODO: Update this method for .NET 4 and remove this section.
bool? createCompilerErrorOnVS2010 = (i = true) ?? j;
#pragma warning restore 0219

The above code will compile with the Visual Studio 2008 compiler but not with the Visual Studio 2010 compiler.

Sander
  • 25,685
  • 3
  • 53
  • 85
  • Neat, we're using the 4.0 tooling, but still on the 3.5 framework. The 4.0 compiler is being used, unfortunately. Cool trick. – John Leidegren Jan 10 '11 at 12:32