0

I know that the C# preprocessor will generally eliminate the precompiled symbols. Can the rule be broken a bit?

For example, I have a C# dll A, which I wanna use in another C# program B. In B I have different precompiled symbols X, Y, Z. If X is defined, I need a version of A. Else if Y is defined, I need another version of A. And similar for Z. To implement this, I want to write precompiled directives in A's source code, like

public static class MyClass
{
    public static void MyMethod()
    {
#if X
        DoX();
#elif Y
        DoY();
#elif Z
        DoZ();
#else
        DoWhatever();
#endif
    }
}

I hope these conditions don't disappear during A's compiling and B can take use of them. Is it possible? Or what should I do to work around this?

Thanks in advance.

EDIT

Some background information. B is a Unity3D Game, and A is a common library we want to use across different games. So Both A and B relies on the assembly UnityEngine.dll. Then there is various precompiled symbols defined by U3D to indicate the current build platform, the engine's version and etc, which I want to take use of in both A and B.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • Do you plan on having 3 copies of A.dll? A.X.dll, A.Y.dll, and A.Z.dll? – Scott Chamberlain Aug 04 '16 at 15:16
  • Directives like `#if` are for conditional compilation. If you want *A* to behave differently based on a condition established in some other program without recompiling *A*, then `#if` is the wrong tool for the job. Have you considered something like a [factory method pattern](https://en.wikipedia.org/wiki/Factory_method_pattern) instead? – Joe Farrell Aug 04 '16 at 15:21
  • @ScottChamberlain I hope not. If I do so, I cannot let _B_ select which _A_ to use, can I? – Garfield the Dummy Aug 04 '16 at 15:22
  • @JoeFarrell Thanks. This IS an option... The application context is more complex... – Garfield the Dummy Aug 04 '16 at 15:23
  • Have you thought about how you would like to "set" the directives for the dll? Via settings? – C.Evenhuis Aug 04 '16 at 15:24
  • @EdPlunkett Thanks for your hint. I think you're right on the fact that I'm far away from mastering this language. – Garfield the Dummy Aug 04 '16 at 15:35
  • 1
    @user1187195 If you don't know a language well, it's often best to state the problem in *semantic* terms. Then you can go into the specifics of how you're trying to implement it. You may totally misunderstand the language constructs you're working with; you may be using a wildly inappropriate idiom by analogy with some other language that does things very differently. The answer can often be "delete all that stuff and do it this totally different way". – 15ee8f99-57ff-4f92-890c-b56153 Aug 04 '16 at 15:40
  • The closest you could get is using [ConditionalAttribute](https://msdn.microsoft.com/en-us/library/system.diagnostics.conditionalattribute(v=vs.110).aspx), but this won't work with the example you gave. What you're trying to do is definitely a smell and really doesn't make much sense. It doesn't seem like the code is actually shared if each thing that's using it has to get a different version. – Kyle Aug 04 '16 at 15:49

2 Answers2

4

Being that B is a Unity3D game what you need to do is just compile your 3 different versions of A and put them in the appropriate default folders for the plugin inspector.

Instead of X, Y, and Z, lets say we have UNITY_EDITOR, UNITY_WSA, and UNITY_IOS.

public static class MyClass
{
    public static void MyMethod()
    {
#if UNITY_EDITOR
        DoX();
#elif UNITY_WSA
        DoY();
#elif UNITY_IOS
        DoZ();
#else
        DoWhatever();
#endif
    }
}

You would need to make 3 copies of A.dll each compiled with the different setting set.

Once you have your 3 dll's you just need to put them in the correct folders in your project to be set to the proper build types automaticly. Your file structure should look like

Assets/Plugins/Editor/A.dll
Assets/Plugins/WSA/A.dll
Assets/Plugins/iOS/A.dll

You don't have to use that structure, but using those folders make them automatically get picked up by the inspector for the correct build types.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
1

In general, you define compiler constants on a project basis. So if your shared assembly defines X and you compile it, it only contains the call to DoX(). Then you compile the actually consuming application where you define Y, but that won't affect the shared assembly.

However, compiler constants can be passed to the compiler using the command line or using XAML, and then apply to all projects that are built at the same time.

How to do so is explained in Is There anyway to #define Constant on a Solution Basis? and MSDN: How to: Declare Conditional Compilation Constants.

So that might be an option: declare them solution-wide and compile the solution as a whole. Do note that your shared assembly then only contains the call corresponding to the constant(s) defined at compile-time: you can't share that assembly with different executables compiled with different constants, because only DoX() will be called if X was declared at compile-time.

Or, rather, you dump this idea altogether and implement the proper design pattern, so the proper method will be called depending on what the caller wants, not who the caller is.

This may mean you should simply expose DoX(), DoY() and DoZ() to the caller, or let MyMethod() do something based on a passed (enum) variable, or something using a strategy pattern.

That being said, there may be reasons to do what you're trying to do, for example not leaking implementation details to competing companies who use your application.

Community
  • 1
  • 1
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Thanks very much for your detailed explanation and links. So I guess in my case it'd be wise to build different versions of the dll. You're right. We don't want to leak implementation details, and in fact we cannot, under the circumstance of Unity3D, put _A_ and _B_ together. – Garfield the Dummy Aug 04 '16 at 15:40
  • 1
    @user1187195 with unity you don't need B to check symbols, all that matters is which folder you put A and B in. See the default settings section of [this unity manual page](http://docs.unity3d.com/Manual/PluginInspector.html). (actually the folder does not matter either, you can change what platform the dll will be used for in the plugin inspector, the folder just sets some defaults in the inspector) – Scott Chamberlain Aug 04 '16 at 15:44