Is there a way to add a preprocessor directive that compares the C# version used by the compiler?
For example :
public T MyMethod<T>()
{
#if CS_7
return default; // Feature 'default literal' is not available in C# 7.0. Please use 7.1 or greater.
#else
return null; // Ignore the fact that this won't work, it isn't the point of the question
#endif
}
Would the .NET version be the way to go here? Wouldn't there be situations where the compiler used is different for the same project? (i.e. if different employess use different versions of Visual Studio)
Apparently you can't, but the C# version used depends on the framework version (list of version per framework) used in the project, which provides a default C# version, unless configured otherwise manually through something like the property (see linked documentation).
Thus, most situations where you would want a C# version preprocessor directive can either be resolved by adding a framework preprocessor directive or forcing a specific C# version in the project itself using the property in the project file.
Related
I work with a code base that contains some code in regular .NET and some code in .NET Core. When I open an individual .cs file, I'm not always sure whether the file was meant to be compiled with regular .NET or .NET Core. Obviously, there's a lot of overlap between both frameworks -- and a lot of code can be run unmodified in both frameworks.
So my question is, what are some easy ways to determine whether a .cs file is intended to be compiled for regular .NET or .NET Core?
(I imagine that looking for certain usings that only exist in one framework or the other is probably the biggest telltale sign. If that is indeed the way to determine this, is there a web page which lists which usings are exclusive to regular .NET vs. .NET Core?)
Your best bet is to look at the .csproj file.
Look for either the <TargetFramework> or the <TargetFrameworks> element. It will have entries such as net461. You can cross reference with the chart here:
https://learn.microsoft.com/en-us/dotnet/standard/frameworks
Microsoft has a Portability Analyzer that will tell you if your code will run on various platforms and what kind of changes are required, but the only way I know to tell what platform particular code was written for is to check the project properties or makefile.
You could also use an if preprocessor directive such as something like this:
public class MyClass
{
static void Main()
{
#if (NETCOREAPP1_0 || NETCOREAPP1_1 || NETCOREAPP2_0 || NETCOREAPP2_1)
<some code>
#else
<some code>
#endif
}
}
I should add that this is a method to use going forward especially with shared code used between NetFramework and Core.
i.e. in PHP, you can build a library of your methods in one file, and error is only given, if there are problems in execution (not in compiler). I wonder if something like that is possible in C#, for example, I could put dedicated methods for both .NET 3.5 and 4.5 in same file:
//myFile.cs
public void mymethod_for_v35(object profile)
public async void mymethod_for_v45(dynamic profile)
so, I could include myfile.cs in all projects (whether targeting 3.5 or 4.5) and when I am targeting 3.5, in application I will only call first method . However, as 2nd method is for 4.5 (and 3.5 net compilers dont understand that), we still get compilation errors in IDE.
Does there exist any workaround or Flag, to allow the existence of that method (even though it's unsupported in current .NET version of project) ?
The most convenient way to achieve this is to use a multi-targeted library via the new SDK project syntax (CSP); start by creating a .NET Standard library, then change the <TargetFramework> to <TargetFrameworks>, simply semi-colon delimiting the frameworks you need to support separately, for example:
<TargetFrameworks>net40;netstandard1.3;netstandard2.0</TargetFrameworks>
(note that other frameworks will be implicitly supported - so if I consume it from a net462 project, the net40 build will be used)
Now add #if checks where needed, for example:
#if NET40
...
#endif
or
#if NETSTANDARD1_3
...
#endif
(note that . is mapped to _)
This means that the appropriate API surface will be surfaced automatically.
If you need to use different references for different target frameworks, that can also be done in the project file via a condition on an item-group:
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="..."/> <!-- whatever you need here -->
</ItemGroup>
At build, each target-framework will be evaluated (including the conditions) and built separately, then bundled together when creating a nupkg.
I'm writing a simple library for my program.
I wrote a lot classes, however after everything done I realize that I need to wrap the files with specific namespaces into #if conditional.
for example, I wrote an alternative implementation of System.Numerics under .NET 2.0:
namespace System.Numerics
{
public class Vector2
{
//.. implementation here
}
}
However, it's only apply if USE_ALTERNATIVE is defined, so if I target into equal or greater than .NET 3.5, I only need to remove USE_ALTERNATIVE from compilation symbol
The class should be like this:
#if USE_ALTERNATIVE
namespace System.Numerics
{
public class Vector2
{
//.. implementation here
}
}
#endif
however, writing #if to all classes under my custom implementations is really tedious work.
is it possible to accomplish this with find and replace that available in Visual Studio?
OK. There is actually a really easy way to do this, and it does not require you to actually use any #if conditionals at all.
Instead, simply put all of your shim classes (that's the technical term for what you're doing) in the same class library project. This will put them all in the same .NET assembly.
Then, in the referencing project, have two different build configurations, targeting different versions of .NET. In the list of references for the 2.0 config, include the library. In the 3.5 config, simply leave it out.
EDIT: Another solution you can use that uses #if conditionals is to wrap the using directives in your client program (instead of your shim classes themselves). That way, you only have to include one #if directive inside each client class that uses your library (and I would assume that your entire project only encompasses one namespace, correct?)
It took me a bit of time to discover this, but designer-specific attributes like TemplatePart are now causing issues with the release build of my UWP application.
Applying this attribute to your controls is using reflection.
[TemplatePart(Name = PART_Panel, Type = typeof(Panel))]
public class MyAwesomeControl : Control
{
...
}
And build output gives me this:
warning : Type 'Windows.UI.Xaml.Controls.Panel' was not included in
compilation, but was referenced in type 'MyAwesomeControl'. There may
have been a missing assembly.
If you want the build to work, I have to exclude that attribute. However, that defeats the purpose of a control library. Users of my library will not know that a Panel with the name PART_Panel is required in the template of MyAwesomeControl.
Is there a solution to this? Do I have to enable reflection for that type just to allow design-time attributes through?
I am aware of the rd.xml file that can be embedded in a project. However, if a <Type Name="Windows.UI.Xaml.Controls.Panel" ... /> is included, doesn't that mean that I'm telling the compiler to exclude that panel from .Net Native optimization?
This is an unfortunate bug in the version of the .Net Native tools (ilc.exe) that you're running on. This attribute is supported properly as of the Update 1 release of Visual Studio. You can get the RC here: https://www.visualstudio.com/en-us/news/vs2015-update1-vs.aspx
You can safely ignore that warning if you're stuck using older tools.
I am creating a .NET assembly. I want to have 2 different versions of this assembly. The only difference between the 2 versions is a guid string which is embedded in a .cs file.
So for version 1 of the assembly, the guid will be ECABAFD2-7F19-11D2-978E-0000F8757E2A and for version 2 ECABAFD2-7F19-11D2-978E-0000F8757E2B
How do I manage something like this in Visual Studio 2010 ? Is there some kind of automation tool that can change that string for me and compile both versions ?
How would you do it ? I am opened to suggestions
In C#, conditional compilation is typically done using ConditionalAttribute. Place code using the relevant GUID values in your assembly that is Conditional on two different compilation symbols - say VARIANT1, VARIANT2.
Define build configurations for this project in Visual Studio that define VARIANT1 for the first build, VARIANT2 for the second build. This results in two output binaries - one with the first GUID and the other with the second.
If you want a slight change perhaps use the #if directive
#if FirstVersion
_id = "ECABAFD2-7F19-11D2-978E-0000F8757E2A"
#else
_id = "ECABAFD2-7F19-11D2-978E-0000F8757E2B"
#endif
Then you either use the command line to compile setting the directive or setup a new configuartion that you can switch.
As for having VS build both at the same time I would suggest a script or external build tool like Nant to do that.