Search code examples
c#unity-game-engineeventsambiguity

Solve ambiguity between itself due to compiler generated copies?


General
Working on a mod for a game using the Unity Engine.

The problem
I'm trying to attach to the activeSceneChanged event with this code:

SceneManager.activeSceneChanged += OnSceneChanged;

This results in the error:

CS0229 Ambiguity between 'SceneManager.activeSceneChanged' and 'SceneManager.activeSceneChanged'

After checking what's going on here, it seems that the activeSceneChanged member is both user generated and [CompilerGenerated]:

enter image description here

What I've tried myself
I honestly have no idea at all how I'd fix an issue like this. I've never encountered it before. Asked a few other devs I know, but they never seen it either. Decompiled the Unity DLL file with ILSpy, only to see that CompilerGenerated code isn't in there (kind of makes sense since it's generated by the compiler I assume).

I'd really like some help on how to approach this issue and solve it.

Edit
To help speed things up, here's a Github link to the mod: https://github.com/skarab42/ValheimTwitch

The error pops up at line 93 in Plugin.cs


Solution

  • Normally, when a class declares an event, the C# compiler emits a public event that is backed by a private field of the same name:

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private static UnityAction<Scene, Scene> activeSceneChanged;
    
    public static event UnityAction<Scene, Scene> activeSceneChanged
    {
        add { ... }
        remove { ... }
    }
    

    But in this case, it seems like the Unity DLL has been modded, with the accessibility of the field changed from private to public. Hence the identifier SceneManager.activeSceneChanged is now ambiguous between the event and the field.

    The ideal solution to this problem is to fix the tool that modded the Unity DLL. It shouldn't change the accessibility of a field when there's an event with the same name.

    In the meantime, you can reference the unmodded Unity DLL, or you can use Reflection to add your event handler:

    typeof(SceneManager).GetEvent("activeSceneChanged").GetAddMethod()
        .Invoke(null, new object[] { (UnityAction<Scene, Scene>)OnSceneChanged });