I have a rather large solution of C# projects in Visual Studio. I want to port some of those projects to work in MONO and to run say on a MAC. Of course some things don't work and some things I don't want to port because they are not applicable on a MAC.
One approach is Solution and Project Configurations. This allows me to exclude projects I don't want to build (unfortunately Visual Studio does not make that easily visible but anyway...).
The second approach which could work in tandem with the first is to use pre compiler directives such as #if MONO and then do something at that point. This is good but then it creates multiple versions of the same assembly. How do I distinguish the two from each other post compile? Is this a problem?
Even if the top two approach work, sometimes I want part of a large project. I don't want to go through 20 or so files and put #if MONO do I? I can highjack the project file by hand but there is no visibility on that whatsoever in visual studio. No one else on the team can tell what's going on unless they unload the project and open the XML and take a look. This sounds quite crazy. To make things worse, sometimes the project references something and I want to exclude the reference for MONO. Now I have to edit the csproj.
I can split the project, but what if at some point I want to port to yet another platform. The intersections of which platform needs what code can get crazy. To make things worse, I can have projects referencing this large project which may then also have to split. This all works but it will cause project overload won't it?
I can't find a good clean solution. Any tips? Is there a standard for this I can follow. If VS had more visibility into the edits of the csproj file, this might work.
Each project will compile to a separate DLL or EXE, a unit of deployment. Namespaces can be spread across projects and solutions and be in different DLLs/EXEs. They are units of logical separation. In Visual Studio, you can set a base namespace for each project in its properties.
You can think of “shared items” projects as another way of organizing your files in case you have many projects building the same source file (e.g. in case you build multiple applications that share the same source and you're not already using static libraries for this purpose).
Build and run your code in Visual Studio To build your project, choose Build Solution from the Build menu. The Output window shows the results of the build process. To run the code, on the menu bar, choose Debug, Start without debugging. A console window opens and then runs your app.
You could also set up a folder structure and split your solution into a common solution which contains platform-independent projects and platform-specific solutions which contain platform-specific projects.
So for example an application.sln containing all your common projects and for the sake of argument we also have a iOS and Android solution.
Within the platform-specific solutions you could reference to the common projects by adding for example a '[application]' folder with additional common project sub-folders to your platform-specific projects. Successively adding all required common files as links.
The above answer is one of the possibilities you could also:
This is a well known programming problem, if solution exists they usually require some work and even more when a project is not designed from scratch to be portable. As you correctly pointed out, pre processed statement will quickly become an overhead and a real pain to maintain and expand over time.
Yet it is not easy to answer this question directly since the solution you are seeking might be highly dependent of your implementation. Generally speaking I would advise you to make extensive use of well known design pattern such as Abstract Factory, Bridge, Facade, etc.
As an exmaple, start by identifying every single piece of code which is platform dependent, define API interfaces responsible to handle these specificities in your core project and implement them into dedicated projects - usually one per platform. Once that's done, go back to your core project and define an interface which will contains factory methods to instantiate these specific classes. Again implements specific factories in their respective projects.
At this point you can decide at runtime which backend you wish to use by selecting the factory who will instantiate your classes. The next step would be to provide some plugable system to load the desired factory at runtime, thanks to the reflection this part is probably the easiest one. You go though every assemblies contained in a special folder, analyse their types to detect if they implement your factory interfaces and if they do : load them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With