开发者

Can I make a preprocessor directive dependent on the .NET framework version?

Here's a concrete example of what I want to do.

Consider the string.Join function. Pre-.NET 4.0, there were only two overloads, both of which required a string[] parameter.

As of .NET 4.0, there are new overloads taking more flexible parameter types, including IEnumerable<string>.

I have a library which includes a Join function that does essentially what the .NET 4.0 string.Join function does. I was just wondering if I could make this function's implementation dependent on the .NET framework being targeted. If 4.0, it could simply call string.Join internally. If 3.5 or older, it could call its own internal implementation.

  1. Does this idea make sense?
  2. If it does make sense, what's the most logical way开发者_StackOverflow to do it? I guess I'm just assuming a preprocessor directive would make the most sense, since a call to string.Join with an IEnumerable<string> parameter won't even compile when targeting a .NET version older than 4.0; so whatever approach I use would have to take place prior to compilation. (Checking the Environment.Version property at runtime, for example, wouldn't work.)


You can take a look at another question on Stack Overflow that illustrates how to set conditional constants through the project file's XML: Detect target framework version at compile time

Then using that you can determine if you should use the .NET 4 overloads or your own library.


Yes, I think it makes sense (for your particular case, since the change is relatively minor), though obviously that sort of thing could scale out of control fairly quickly.

IMHO, the most logical way to go about it would be to create different solution/project configurations for each version, then define a custom symbol (say, NET40) in your 4.0 configurations, then use that with an #if. I'm not certain if configurations will allow you to change the runtime version (that would obviously be the perfect solution), but your worst-case is having to change the version manually.

EDIT: I just saw the answer linked to in Joshua's answer, and that seems like a more streamlined solution, but I'll leave this here anyway, since it does, strictly speaking, answer the question.


You can prepare your code for .NET 4.0 and write the similar code for the .NET 3.5 base on framework detection.

#if NOT_RUNNING_ON_4
public static class GuidExtensions
{
   public static bool TryParse(this string s, out Guid result)
   {
       if (s.IsNullOrEmpty())
           return null;
       try
       {
          return new Guid(s);
       }
       catch (FormatException)
       {
          return null;
      }
   }
}
#else
    #error switch parsing to .NET 4.0
#endif

And put his line to your *.csproj

<DefineConstants Condition=" '$(TargetFrameworkVersion)' != 'v4.0' ">NOT_RUNNING_ON_4</DefineConstants>


At some point (not sure when), Microsoft added predefined symbols for .NET versions into the MSBuild build system. Everything here works if you are using MSBuild from the .NET 5+ SDK (even if the project you are building with that SDK is using a much older target framework).

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives

Target Frameworks Symbols Additional symbols available in .NET 5+ SDK
.NET Framework NETFRAMEWORK, NET48, NET472, NET471, NET47, NET462, NET461, NET46, NET452, NET451, NET45, NET40, NET35, NET20 NET48_OR_GREATER, NET472_OR_GREATER, NET471_OR_GREATER, NET47_OR_GREATER, NET462_OR_GREATER, NET461_OR_GREATER, NET46_OR_GREATER, NET452_OR_GREATER, NET451_OR_GREATER, NET45_OR_GREATER, NET40_OR_GREATER, NET35_OR_GREATER, NET20_OR_GREATER
.NET Standard NETSTANDARD, NETSTANDARD2_1, NETSTANDARD2_0, NETSTANDARD1_6, NETSTANDARD1_5, NETSTANDARD1_4, NETSTANDARD1_3, NETSTANDARD1_2, NETSTANDARD1_1, NETSTANDARD1_0 NETSTANDARD2_1_OR_GREATER, NETSTANDARD2_0_OR_GREATER, NETSTANDARD1_6_OR_GREATER, NETSTANDARD1_5_OR_GREATER, NETSTANDARD1_4_OR_GREATER, NETSTANDARD1_3_OR_GREATER, NETSTANDARD1_2_OR_GREATER, NETSTANDARD1_1_OR_GREATER, NETSTANDARD1_0_OR_GREATER
.NET 5+ (and .NET Core) NET, NET6_0, NET5_0, NETCOREAPP, NETCOREAPP3_1, NETCOREAPP3_0, NETCOREAPP2_2, NETCOREAPP2_1, NETCOREAPP2_0, NETCOREAPP1_1, NETCOREAPP1_0 NET6_0_OR_GREATER, NET5_0_OR_GREATER, NETCOREAPP3_1_OR_GREATER, NETCOREAPP3_0_OR_GREATER, NETCOREAPP2_2_OR_GREATER, NETCOREAPP2_1_OR_GREATER, NETCOREAPP2_0_OR_GREATER, NETCOREAPP1_1_OR_GREATER, NETCOREAPP1_0_OR_GREATER

This allows you to, for example, do this:

#if NET5_0_OR_GREATER
    Console.WriteLine("This is .NET 5 or later.");
#elif NETCOREAPP
    Console.WriteLine("This is an older version of .NET Core.");
#elif NETFRAMEWORK
    Console.WriteLine("This is the legacy .NET Framework.");
#else
    Console.WriteLine("This is something else.");
#endif
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜