I created a project in Visual Studio 2017 RC to check whether I can use new C# 7.0 language features in a .NET Framework 4.5 project. It seems to me that after referencing System.ValueTuple NuGet, new tuples are working fine. Is there anything else I should think about, or is this going to work?
After checking System.ValueTuple NuGet dependencies, it looks like .NET Framework 4.0 is not supported. Is this the case, or is there some way to make the new language work in this runtime also?
Let's go through the features new in C# 7.0:
Tuples: The System.ValueTuple package has a version for the portable-net40+sl4+win8+wp8 profile. That means it is usable on .Net 4.0. (Not sure why dependencies list only .Net 4.5.)
If you wanted to use tuples on even lower versions of .Net, it should still work, as long as you add the code for ValueTuple and related types to your project.
out variables, pattern matching, local functions, more expression-bodied members, throw expressions, numeric literal syntax improvements: All these features are just syntax sugar, so they don't need any new capabilities from the framework.
ref locals and returns: This feature exposes in C# what the framework supported since the start, so no changes in the framework are needed here either.
Generalized async return types: To use this feature, you need a type that has the AsyncMethodBuilder attribute, which is in the System.Threading.Tasks.Extensions package (along with one such type, ValueTask<T>). This package is only supported on .Net 4.5, so for .Net 4.0, you would need to compile the relevant types yourself. (Using await on .Net 4.0 also requires Microsoft.Bcl.Async, but that's nothing new.)
To sum up: All of C# 7.0 should work on .Net 4.5 after installing the required packages and most of it should work on .Net 4.0 too.
Running a C# 7 compiled application on .NET 4.5 should be fine at this moment, but note that running ASP.NET applications that use ASP.NET Dynamic Compilation won't work on .NET 4.5 because the C# 7.0 compiler requires .NET 4.6 to run.
Source: https://github.com/dotnet/roslyn/issues/17908:
The C# 7.0 compiler (2.0 and higher) requires .NET 4.6 to run
The information on https://www.nuget.org/packages/Microsoft.Net.Compilers/2.0.1 (about supporting .NET 4.5) seems to be outdated.
Related
In Visual Studio 2019 Advanced Build settings, C# 8 does not appear to be available for a .NET Framework project, only (as in the picture below) for a .NET Core 3.0 project:
Does C# 8 support the .NET Framework?
Yes, C# 8 can be used with the .NET Framework and other targets older than .NET Core 3.0/.NET Standard 2.1 in Visual Studio 2019 (or older versions of Visual Studio if you install a NuGet package).
The only thing required is to set language version to 8.0 in the csproj file. You can also do this in Directory.Build.props to apply it to all projects in your solution. Read below for how to do this in Visual Studio 2019, version 16.3 and newer.
Most - but not all - features are available whichever framework is targeted.
Features that work
The following features are syntax changes only; they work regardless of framework:
Static local functions
Using declarations
Null-coalescing assignment
Readonly members
Disposable ref structs
Positional patterns
Tuple patterns
Switch expressions
Nullable reference types are also supported, but the new nullable attributes required to design the more complex nullable use cases are not. I cover this in more detail further down in the "gory details" section.
Features that can be made to work
These require new types which are not in the .NET Framework. They can only be used in conjunction with "polyfill" NuGet packages or code files:
Asynchronous streams - Microsoft.Bcl.AsyncInterfaces
Indices and ranges
Default interface members - do not, cannot, and never will work
Default interface members won't compile under .NET Framework and will never work because they require runtime changes in the CLR. The .NET CLR is now frozen as .NET Core is now the way forward.
For more information on what does and doesn't work, and on possible polyfills, see Stuart Lang's article, C# 8.0 and .NET Standard 2.0 - Doing Unsupported Things.
Code
The following C# project targetting .NET Framework 4.8 and using C# 8 nullable reference types compiles in Visual Studio 16.2.0. I created it by choosing the .NET Standard Class Library template and then editing it to target .NET Framework instead:
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48</TargetFrameworks>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
.cs:
namespace ClassLibrary1
{
public class Class1
{
public string? NullableString { get; set; }
}
}
I then tried a .NET Framework 4.5.2 WinForms project, using a legacy .csproj format, and added the same nullable reference type property. I changed the language type in the Visual Studio Advanced Build settings dialog (disabled in 16.3) to latest and saved the project. Of course as this point it doesn't build. I opened the project file in a text editor and changed latest to preview in the build configuration PropertyGroup:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<LangVersion>preview</LangVersion>
I then enabled support for nullable reference types by adding <Nullable>enable</Nullable> to the main PropertyGroup:
<PropertyGroup>
<Nullable>enable</Nullable>
I reloaded the project, and it builds.
Visual Studio 2019
There has been a major change in the RTM version of Visual Studio 2019 version 16.3, the launch version for C# 8.0: the language selection dropdown has been disabled:
Microsoft's rationale for this is:
Moving forward, ... each version of each framework will have a single
supported and default version, and we won't support arbitrary
versions. To reflect this change in support, this commit permanently
disables the language version combo box and adds a link to a document
explaining the change.
The document which opens is C# language versioning. This lists C# 8.0 as the default language for .NET Core 3.x ONLY. It also confirms that each version of each framework will, going forward, have a single supported and default version and that the framework-agnosticism of the language can no longer be relied on.
The language version can still be forced to 8 for .NET Framework projects by editing the .csproj file.
The gory details
When this answer was first written, C# 8 was in preview and a lot of detective work was involved. I leave that information here for posterity. Feel free to skip it if you don't need to know all the gory details.
The C# language has historically been mostly framework neutral - i.e. able to compile older versions of the Framework - although some features have required new types or CLR support.
Most C# enthusiasts will have read the blog entry Building C# 8.0 by Mads Torgersen, which explains that certain features of C# 8 have platform dependencies:
Async streams, indexers and ranges all rely on new framework types
that will be part of .NET Standard 2.1... .NET Core 3.0 as well as
Xamarin, Unity and Mono will all implement .NET Standard 2.1, but .NET
Framework 4.8 will not. This means that the types required to use
these features won’t be available on .NET Framework 4.8.
This looks a bit like Value Tuples which were introduced in C# 7. That feature required new types - the ValueTuple structures - which were not available in NET Framework versions below 4.7 or .NET Standard older than 2.0. However, C# 7 could still be used in older versions of .NET, either without value tuples or with them by installing the System.ValueTuple Nuget package. Visual Studio understood this, and all was fine with the world.
However, Mads also wrote:
For this reason, using C# 8.0 is only supported on platforms that implement .NET Standard 2.1.
...which if true would have ruled out using C# 8 with any version of the .NET Framework, and indeed even in .NET Standard 2.0 libraries which only recently we were encouraged to use as a baseline target for library code. You wouldn't even be able to use it with .NET Core versions older than 3.0 as they too only support .NET Standard 2.0.
The investigation was on! -
Jon Skeet has an alpha version of Noda-Time using C# 8 ready to go which targets .NET Standard 2.0 only. He is clearly expecting C# 8/.NET Standard 2.0 to support all frameworks in the .NET family. (See also Jon's blog post "First steps with nullable reference types").
Microsoft employees have been discussing the Visual Studio UI for C# 8 nullable reference types on GitHub, and it is stated that they intend to support the legacy csproj (pre-.NET Core SDK format csproj). This is a very strong indication that C# 8 will be usable with the .NET Framework. [I suspect they will backtrack on this now that the Visual Studio 2019 language version dropdown has been disabled and .NET has been tied to C# 7.3]
Shortly after the famous blog post, a GitHub thread discussed cross-platform support. An important point which emerged was that .NET Standard 2.1 will include a marker that denotes that default implementations of interfaces is supported - the feature requires a CLR change that will never be available to the .NET Framework. Here's the important bit, from Immo Landwerth, Program Manager on the .NET team at Microsoft:
Compilers (such as C#) are expected to use the presence of this field to decide whether or not to allow default interface implementations. If the field is present, the runtime is expected to be able to load & execute the resulting code.
This all pointed to "C# 8.0 is only supported on platforms that implement .NET Standard 2.1" being an oversimplification, and that C# 8 will support the .NET Framework but, as there is so much uncertainty, I asked on GitHub and HaloFour answered:
IIRC, the only feature that definitely won't appear on .NET Framework is DIM (default interface methods) as that requires runtime changes. The other features are driven by the shape of classes that might never be added to the .NET Framework but can be polyfilled through your own code or NuGet (ranges, indexes, async iterators, async disposal).
Victor Derks commented that "The new nullable attributes required to design the more complex nullable use cases are only available in System.Runtime.dll that ships with .NET Core 3.0 and .NET Standard 2.1... [and] incompatible with .NET Framework 4.8"
However, Immo Landwerth commented that "The vast majority of our APIs didn't need any custom attributes as the types are either fully generic or not-null" under the article Try out Nullable Reference Types
Ben Hall raised the issue Availability of nullable attributes outside of Core 3.0 on GitHub, with the following comments from Microsoft employees being of note:
C# 8 will be fully supported on .net core 3.0 and .net standard 2.1 only.
If you manually edit the project file to use C# 8 with .net core 2.1,
you are in unsupported territory. Some C# 8 features will happen to
work well, some C# 8 features will work not too well (e.g. poor
performance), some C# 8 features will work with extra hacks, and some
C# 8 features will not work at all. Very complex to explain. We do not
actively block it so the expert users who can navigate through it can
do so. I would not recommend this unsupported mix&match to be used
broadly.
(Jan Kotas)
People like you who are willing understand -- and work around them --
are free to use C# 8. The point is, not all language features will work
on down-level targets.
(Immo Landwerth)
Caveat emptor
The C# 8/.NET Framework combination is not officially supported by Microsoft. It is, they say, for experts only.
According to this blog entry the language is indeed tied to the framework:
This means that the types required to use these features won’t be available on .NET Framework 4.8. Likewise, default interface member implementations rely on new runtime enhancements, and we will not make those in the .NET Runtime 4.8 either.
For this reason, using C# 8.0 is only supported on platforms that implement .NET Standard 2.1. The need to keep the runtime stable has prevented us from implementing new language features in it for more than a decade. With the side-by-side and open-source nature of the modern runtimes, we feel that we can responsibly evolve them again, and do language design with that in mind. Scott explained in his Update on .NET Core 3.0 and .NET Framework 4.8 that .NET Framework is going to see less innovation in the future, instead focusing on stability and reliability. Given that, we think it is better for it to miss out on some language features than for nobody to get them.
I'm using C# 8.0 (beta) in my UWP app with Visual Studio 2019 v16.0.2.
I was trying to use the new range operator of C# 8 : str[start..index] and then two errors showed up:
Predefined type System.Range is not defined or imported
Predefined type System.Index is not defined or imported
But there is no such reference that I could use.
Visual Studio itself suggested me to use this feature. Is that the feature hasn't made available yet or what?
This is a part of .NET Core 3 which is not released yet.
Indices and Ranges is a part of C# 8.0, which was released together with .NET Core 3.0 in September 2019. To use all of the C# 8.0 features, your target framework must be one of the following:
.NET Standard 2.1
.NET Core 3.0 and later
.NET 5.0 and later
It is also possible to use C# 8.0 features on earlier versions of .NET, such as .NET Standard 2.0 and .NET Framework. To do this you need to override the default C# version on your project. However, Indices and Ranges is not officially supported on these earlier versions and will not work out-of-the-box. That being said, there is a possible workaround to make it work: https://www.meziantou.net/how-to-use-csharp-8-indices-and-ranges-in-dotnet-standard-2-0-and-dotn.htm
I maintain a .NET 2.0 library (currently, using Visual Studio 2013).
I have used a code-inspection tool on the code of the library and was surprised when the tool suggested using ?? operator or lambdas instead of some of the code.
I was even more surprised when I applied suggested edits and the library was successfully built after that.
Why the library with Target Framework set to .NET Framework 2.0 can be built with newer features of C# in it's code?
Is it safe to use newer C# features when building for older .NET Framework versions? I mean, the users of the library can have .NET Framework 2.0 only and I want them to be able to use the library even if I use lambdas in it's code.
.NET 2.0 and C# 2.0 are 2 different things. In your case you could perfectly fine have a .NET 2.0 library (which is targeting the CLR 2.0) and use the C# 3.0 compiler which supports for example lambda expressions.
So you should make a difference between your compiler version and the version of the CLR you are targeting. Since you are using VS 2013, you could use newer versions of the compiler.
Is it safe to use newer C# features when building for older .NET Framework versions?
Yes, perfectly safe. The generated assembly is still targeting the CLR 2.0 and will run without any issues with this older version of the CLR.
Basically, new C# language features can be implemented in the compiler without requiring extensions to the underlying .net framework. It isn't always done like that, but it may be.
In the case of lambdas, they were introduced in C# 3.0. So you need a compiler of that level or above. However, the new features introduced in C# 3.0 were all built using the features of .net 2.0. So you can use lambdas under .net 2.0.
In essence, the new functionality here is implemented in the compiler rather than the framework.
As for the null-coalescing operator, ??, it was introduced in C# 2.0 so there's nothing surprising about being able to use it under .net 2.0.
Development Environment :
- VS2010
- .Net Framework 4.0, 3.5, 2.0
Staging and Production Environments:
- .Net Framework 3.5, 2.0
The project I'm working on is targeting .Net Framework 3.5. And today I used optional parameters feature, which is new to C#4, in this project and it worked fine. I think VS2010 is using C#4 compiler and is compiling the method with optional parameters to corresponding overloaded methods in IL.
I want to know if I can use all new C#4 features as well.
You cannot use is the dynamic feature. This relies on the C# runtime and DLR DLL's which are only available on the 4.0 version of the .Net framework. Versions of the DLR are available for 3.5 but I do not believe they are compatible with the one required by the C# compiler.
Additionally you cannot use NoPIA / Embedded Interop Types in a down targetted scenario. This feature requires CLR support that was added in 4.0.
What's great about down targeting in Visual Studio 2010 though is you don't have to be aware of every limitation. If your projects are set to down target 3.5 and you use an incompatible feature, Visual Studio will produce an error.
I bumped into this a couple of weeks ago actually. I used optional parameters even though the project targeted .net 3.5. You need to be very careful of this because if you install the application on a computer that only has .net 3.5 runtime installed then your program may not run. In my case, I used the optional params and the nightly build server only had 3.5 installed so the build failed.
I have a dll which is based on .net 3.5 -- it uses internally for example Linq, but the exposed API is straightforward, no fancy stuff. Since C# generics are resolved at compile time I assume that for calling party all it counts is API (all public parts).
However when I try to use this dll from net2.0 project I get info, that the dll cannot be referenced because the dll or one of its dependencies requires a later version of .net framework.
I can install any .net version I want on target computer (when entire app is installed), but I cannot change .net version for the project itself.
So: how to solve this? When adding a C dll to this project I had no such problems, so are C# dlls self-contained or not?
C# dlls need to have the .Net runtime to run as they are not compiled down to machine code. In this case the dll says it requires Net 3.5 so all your project will have to use 3.5 or higher.
To keep your project as Net 2.0 you would need to build another executable to contain the 3.5 DLL and communicate across separate processes.
The C DLL worked as it is compiled down to native code and does not require the .Net framework. (or at least not version higher than 2.0)
I've been using System.Core and the new System.Web.Extensions (for example) from 3.5 in an ASP.NET 2.0 app (using VS2005) for a while now with no problems. Similar to what Scott Hanselman blogged about here. So yes, it's possible.
.NET 3.5 still runs on the same CLR as .NET 2.0. So at runtime it's all the same. (Assuming you've tracked down any dependencies and copied those 3.5 DLLs to your bin folder as well.)
The only real limitation is what C# language features you can use at development time. Such as 'var', extension methods, or LINQ query syntax.
If you are using linq to objects, then you can use Linq Bridge:
http://www.albahari.com/nutshell/linqbridge.aspx
this is a Linq to objects implementation for .net 2.0.
You will still have to compile using vs2008 but you can compile with .net 2.0 as a target platform in that case.
(This is because the C# 3 compiler understands linq clauses even if you target .net 2.0, it will simply resolve the calls to linqbridge instead of the .NET 3.5 libraries in this case)
If you're using .NET 3.5 libraries then your application's requirements should be such that any consumer of it's API's should also be using .NET 3.5.
The only way you can bypass this is if you package all the dependencies of your application along with it. This means libraries your application uses which depend on the .NET 3.0 and 3.5 frameworks.
However, I'm not sure of the legality of ripping out chunks of the .NET frameworks and packaging them with an app. I'd read the EULA before doing anything like this. IMO, it's not worth the hassle; just install 3.5, ask your users to install 3.5 and be done with it or use only 2.0 features and libraries. At the very least, hacking around like this will only cause you more pain with deployment if there are framework updates in the future.
In either case, your app will work on .NET 2.0 as 3.0 and 3.5 are just extra libraries on top of the 2.0 runtime and libraries (as Craig mentioned) as long as all your dependencies are there.
C# DLLs are not self-contained. If your 3.5 DLL needs LINQ, it depends on system assemblies from the 3.5 (3.0 to be exact) framework, therefore the entire application depends on this version.
You could load the 3.5 assembly dynamically and use reflection to get access to the functions you need. This requires some overhead, of course.
Nothing pretty but there are ways to get the code happily working together (in the order of preference):
1) Upgrade both projects to 3.5
If I understand you correctly then your .net FW 2.0 Program will have dependency on 3.5 Library, which means for every functionality of the Program to work, it now requires FW 3.5. Since you state to have the code and authority to recompile the the Program AND install whatever FW on deployment, then you can upgrade it to 3.5. Sounds simple, but since you did not do this, then I guess you have good reasons (like other programs being higher up the call chain which you cannot upgrade to 3.5/recompile.)
2) Go around the FW2.0 compiler
Build the Program when referencing the 2.0 version of Library (or dummy, just providing the public API).
Build the 3.5 version of Library separately without Program (hence removing the need to reference the wrong FW assembly) and deploy the 3.5 version instead of the 2.0 version.
Since 2.0 and 3.5 use the same CLR runtime then fooling the compiler is enough. As long as the deployment maching has FW 3.5 installed, everything should be fine.
Note: everything is fine even if you have just .net 2.0 present on deployment machine and the user does not call .net 3.5 classes. If he does, there will be crash ;)
3) downgrade Library to 2.0
if you use only some classes of the .net FW then you could remain using the 2.0 compiler by adding those missing future assemblies to project. (this is the solution from Hanselman link shared by Craig). As already noted, you'll lose 3.5 compiler's syntactic sugar like vars.
Choose whichever suits your situation best.