C# Compiler and dynamic class

I have some questions about the C# compiler.

Why can’t we compile class with different definitions? We are talking about dynamic classes.

Like this one:

#if UNITY_EDITOR
public class MyClass : EditorClass
#elif UNITY_ANDROID
public class MyClass : AndroidClass
#elif ...
...
#endif

And we have public variables with same name in BaseClass that both EditorClass and AndroidClass are based on. The code are philosophically correct but we will get compiler error.

There are workarounds for sure, like building a paradoxacial code where ChildClass depends on MyClass.

But why getting errors for this one?

This is something is probably better handled through a service locator pattern, rather than solely through inheritance.

Sure but it was not wrong by C# definition, the compiler should handle this.

MyClass : ClassA : BaseClass
MyClass : ClassB : BaseClass

The public variables from BaseClass are shown in the inspector but the ClassA and ClassB is compiled to platform-specific while using shared core code. This should effectively reduce lines of code.

I mean it would help if you said what the compiler errors were.

You meant to say “It’s technically valid”. Philosophy has nothing to do with it. Nor are these “dynamic” classes, they are switching their base class on compile time, that’s AOT (ahead of time) compilation switches while truly dynamic would be able to switch at runtime (Service locator mentioned above).

It’s a highly questionable use case. It’s polymorphism gone wrong. You will very likely often run into “build failed” errors due to MyClass using an API that doesn’t exist or changes when building for Android. Most importantly the code within MyClass would still require compile-time switches of UNITY_EDITOR vs UNITY_ANDROID symbols or runtime type checks in order to know what its base class is - so this just complicates any code you write by another level of indirection.

Any compile errors you are getting is almost certainly due to the EditorClass and AndroidClass not sharing the same API. So either the code in MyClass complains about unknown methods or mismatching signatures, or it’s complaining that the base classes require separate implementations of abstract (interface) methods.

Yeah, best to avoid this.
Tried to do something similar at one point and Unity’s build process just doesn’t like it (even if it logically should work).
It seems like there are some analysis steps running before the macros are applied.

Better and cleaner is to extract the class independent functional code into a third class and inherit from it from two separate classes in different assemblies (where one is editor only). Or ideally make all functionality of that third class static so you don’t need to bother with inheritance.

You are correct, this is the issue. The execution of code changed after the compiling process depending on the platform definition. The base class are two different classes to the compiler, but the variable and function names are duplicated, this is where errors shown up. But this does not mean it is unsolvable.

Virtual and abstract objects in a external fixed class does solve this case but not the compiling process with this definition of class. The overrided objects are still duplicated.

Do you have a specific example? Because the thing you claim we “can’t compile” is actually very compilable.

#define FOO
using UnityEngine;

#if FOO
public class TestScript : A {}
#else
public class TestScript : B {}
#endif

public class BaseClass : MonoBehaviour {}

public class A : BaseClass
{
    public string aString;
}

public class B : BaseClass
{
    public string bString;
}

This compiles, you can add TestScript to a MonoBehaviour, and if you remove #define FOO, the inspector changes from showing aString to showing bString.

using UnityEngine;

#if !UNITY_EDITOR
public class TestScript : A
#else
public class TestScript : B
#endif
{
    void Start()
    {
        Debug.Log(bString);
    }
}

public class BaseClass : MonoBehaviour 
{
    public string bString;
}

public class A : BaseClass
{
    // Empty
}

public class B : BaseClass
{
    // Empty
}

This was the code I got errors when compiling to Android.

That’d get compiler errors on any platform since you misspelled Debug :stuck_out_tongue:

If I fix that your example compiles on Android.

Edited the post, typed it with phone. Not easy with autocorrect. Thank you.

It would help if you could post the compiler error. You might have simply forgotten to wrap editor code or using UnityEditor; inside a #if UNITY_EDITOR block.

Yes, until we know what the errors are, this entire thread is just a shot in the dark. It could be due to something entirely unrelated for all we know.

Seems like the code compiles fine now and not crashes in the device. My guess is the Managed Stripped Level fixed the issue. In the earlier Unity versions had Disabled button. Now it have Minimal instead of Disabled.

Disabled means that no code was stripped, while minimal means that only some code was removed. So, if earlier versions used “disabled” and it is now set to “minimal” this is certainly not the reason the code would fail to compile.

I just tried Managed Stripped Level with Disabled in Mono, I was not able to reproduce the error. Also disabled “Use Deterministic Compilation” didn’t affected. Tricking the compiler with turing on/off different #define to keep some in the cache didn’t affected it.

I will try again with a project in a computer with a another operation system, specific Unity version and the player settings remains the same where I remembered producing the error.