Wrap namespaces into conditional symbol (#if) - c#

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?)

Related

How to tell if code is written for regular .NET or .NET Core?

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.

Is there an equivalent to Python's ImportError in C#

I'm putting together a code base for Unity3d with all sorts of common patterns. It will be imported into a project as source code not a compiled DLL.
Some of the code should only be compiled where a specific dependency (also installed as source code) is present. (In this case, Networking code should only be compiled if Photon is installed in the project).
I could just go through manually delete files that aren't required, however I would prefer some kind of automated way to conditionally compile classes.
If this where Python I could do something like:
try:
import MyLibrary
class MyClass(self):
...
except ImportError:
# library not imported
I know within a class I can use reflection to work out if a class is defined, but is there a way to do this at a higher level, i.e. with something like the pseudocode:
#if namespace_defined('ExternalDependency') // <-- how can I do this kind of check?
using ExternalDependency;
public class MyClass { ... }
#endif
In C#, there's no chance that you could include an using clause in a code file as part of a project which doesn't reference the assembly that contains the imported namespace, thus, you won't be able to perform that check.
An using of a namespace which can't be located in any of referenced assemblies will produce a compiler error (i.e. Are you missing a project reference?).
In other words, C# encourages developers to be sure that all dependencies are available at compile-time.
Actually, if you want to perform different actions in your code depending on some configuration, environment or whatever, it seems like you'll need to stick with inversion of control design pattern.

Implement interface depending on framework version

I'm writing a library, and I want a class to implement and make use of IReadOnlyList<T> if possible. However, that interface is only available starting at framework version 4.5, and I don't want to be tied to that version just because of this one interface.
Is there a way I can automatically compile two versions of the library, one for 4.5 (that will implement the interface, and possibly have some other features as well), and another for 3.5?
As an example, I'm looking for something like an MSBuild configuration that says "compile this library in two [or more] versions" and then specify different options for each one, like defined symbols, framework, references, etc.
If this is possible, it could actually solve a number of other similar problems I've been having.
You could use a compiler directive, e.g.
#if NET45
//specific code for .NET 4.5
#endif
Then create two projects, one for each version, using the Project Linker to maintain a single codebase. In the .NET 4.5 project you can specify the NET45 variable on build. This way the code in the #if block will only be used in one of the versions.
You can make two versions of the project file, targeting different framework versions. In this case I would place all the project files in the existing project directory.
In each project, you would define a symbol indicating the framework version (as needed), for example DOTNET45. You can do this under Properties - Build - Conditional Compilation Symbols
Then you can use the #if directive:
class MyClass<T> : IList<T>
#if DOTNET45
, IReadOnlyList<T>
#endif
{
// Your usual code
#if DOTNET45
// IReadOnlyList implementation
#endif
}
This could get messy however. So alternatively, you could use partial classes:
partial class MyClass<T>
{
}
#if DOTNET45
partial class MyClass<T> : IReadOnlyList<int>
{
// IReadOnlyList implementation
}
#endif
Obviously partial classes can also be divided over files, so potentially you could do without #if altogether, by only including this partial class file in the .NET 4.5 version of the project.

Do Portable Class Libraries handle conditional statements / references?

I have a class library that I am sharing between .Net Framework and Silverlight using two linked projects and the linked-files technique.
I'd like to convert that to a single Portable Class Library, but I have one bit of code that is different between the two. I currently use a conditional compiler statements to separate the implementations of this one file.
#if SILVERLIGHT
...
#else
...
#endif
Will this be honored in the PCL?
Also, the part of code that is NOT silverlight makes reference to a third-party regular .Net class library. The PCL still compiles, but I cannot use it in Silverlight because of this reference. Is there any way to tell the PCL to only include it for the .Net usage?
That pattern implements compile-time portability instead of run-time portability.
If you have tons of Silverlight-specific code, then you don't really have a portable library--you should consider factoring out the Silverlight-specific code to a separate assembly and having that specialized assembly take a dependency on your PCL.
If you have very little Silverlight-specific code, you could consider binding to your Silverlight dependencies dynamically at run-time using reflection. Your PCL can then be used in any context, but will "gracefully upgrade" to Silverlight if Silverlight is present.

How to force a C# root namespace throughout project files for when none is coded?

I want to force a root namespace on the contents of any .cs source files that don't have their contents wrapped in an explicit namespace. In other words I want to keep classes and other namespace-level structures out of the default namespace.
(Working inside a Windows .NET environment with Visual Studio)
In the following example, I want to force the Car class into the MotorIndustry namespace by default even though it has no explicit namespace coded.
Vehicle.cs (has namespace)
namespace MotorIndustry {
public class Vehicle {
// ...
}
}
Car.cs (no namespace/default)
public class Car : Vehicle {
//...
}
Is there a way to accomplish this "root namespace" modification behaviour through project settings in Visual Studio, AssemblyInfo.cs file or some other means?
My understanding is VB.NET has a feature like this but C# acts differently?
Some context about why am I asking this: I have hundreds of classes and the programmer forgot to wrap the namespace around some. When I reference the assembly from other projects it's polluting the default namespace with classes that end up causing some ambiguous situations.
Use ReSharper to move the classes into the proper namespace. In fact, version 5.0 (still in Beta) allows you to correct namespaces globally.
The other way to do it is to make the other developer fix the code.
It sounds like you are trying to replicate VB.Net's project namespace feature in C#. This is not a supported feature of the C# compiler or IDE. You will not be able to create one by modifying a project file. You will need to add the namespace to every file in the project either manually or via a tool.

Categories