Code generation for partial struct causes Unity to throw error because of duplicated class

Not sure if this is the appropriate place to post this but I am having issues when attempting to define partial structs for IJobEntity, specifically if that Job resides in a class that inherits from ScriptableObject or MonoBehaviour. I get the following error message: Temp\GeneratedCode\Assembly-CSharp\ErrorExample__JobEntity_1406895720.g.cs(8,14): error CS0101: The namespace ‘’ already contains a definition for ‘ErrorExample’

Example of code that causes this problem:

ErrorExample.cs:

using Unity.Collections;
using Unity.Transforms;
using UnityEngine;
using Unity.Entities;

public class ErrorExample : MonoBehaviour {
    [GenerateTestsForBurstCompatibility]
    private partial struct ErrorExampleJob : IJobEntity {
        public void Execute(in LocalTransform localTransfrom) {
            // something here
        }
    }
}

Generated code for ErrorExample.cs

#pragma warning disable 0219
#line 1 "<system path was here>\Temp\GeneratedCode\Assembly-CSharp\ErrorExample__JobEntity_1406895720.g.cs"
using Unity.Collections;
using Unity.Transforms;
using UnityEngine;
using Unity.Entities;

public class ErrorExample : MonoBehaviour
{
    [global::System.Runtime.CompilerServices.CompilerGenerated]
    partial struct ErrorExampleJob : global::Unity.Entities.IJobChunk, global::Unity.Entities.InternalCompilerInterface.IIsFullyUnmanaged
    {
        [Unity.Collections.ReadOnly]
        public Unity.Entities.ComponentTypeHandle<Unity.Transforms.LocalTransform> __Unity_Transforms_LocalTransformComponentTypeHandle;
        [global::System.Runtime.CompilerServices.CompilerGenerated]
        public void Execute(in ArchetypeChunk chunk, int chunkIndexInQuery, bool useEnabledMask, in Unity.Burst.Intrinsics.v128 chunkEnabledMask)
        {
            var localTransformArray = InternalCompilerInterface.UnsafeGetChunkNativeArrayReadOnlyIntPtr<Unity.Transforms.LocalTransform>(chunk, ref __Unity_Transforms_LocalTransformComponentTypeHandle);
            int chunkEntityCount = chunk.Count;
            int matchingEntityCount = 0;
            if (!useEnabledMask)
            {
                for (int entityIndexInChunk = 0; entityIndexInChunk < chunkEntityCount; ++entityIndexInChunk)
                {
                    ref var localTransformArrayRef = ref InternalCompilerInterface.UnsafeGetRefToNativeArrayPtrElement<Unity.Transforms.LocalTransform>(localTransformArray, entityIndexInChunk);
                    Execute(in localTransformArrayRef);
                    matchingEntityCount++;
                }
            }
            else
            {
                int edgeCount = Unity.Mathematics.math.countbits(chunkEnabledMask.ULong0 ^ (chunkEnabledMask.ULong0 << 1)) + Unity.Mathematics.math.countbits(chunkEnabledMask.ULong1 ^ (chunkEnabledMask.ULong1 << 1)) - 1;
                bool useRanges = edgeCount <= 4;
                if (useRanges)
                {
                    var enabledMask = chunkEnabledMask;
                    int entityIndexInChunk = 0;
                    int chunkEndIndex = 0;
                    while (EnabledBitUtility.GetNextRange(ref enabledMask, ref entityIndexInChunk, ref chunkEndIndex))
                    {
                        while (entityIndexInChunk < chunkEndIndex)
                        {
                            ref var localTransformArrayRef = ref InternalCompilerInterface.UnsafeGetRefToNativeArrayPtrElement<Unity.Transforms.LocalTransform>(localTransformArray, entityIndexInChunk);
                            Execute(in localTransformArrayRef);
                            entityIndexInChunk++;
                            matchingEntityCount++;
                        }
                    }
                }
                else
                {
                    ulong mask64 = chunkEnabledMask.ULong0;
                    int count = Unity.Mathematics.math.min(64, chunkEntityCount);
                    for (int entityIndexInChunk = 0; entityIndexInChunk < count; ++entityIndexInChunk)
                    {
                        if ((mask64 & 1) != 0)
                        {
                            ref var localTransformArrayRef = ref InternalCompilerInterface.UnsafeGetRefToNativeArrayPtrElement<Unity.Transforms.LocalTransform>(localTransformArray, entityIndexInChunk);
                            Execute(in localTransformArrayRef);
                            matchingEntityCount++;
                        }

                        mask64 >>= 1;
                    }

                    mask64 = chunkEnabledMask.ULong1;
                    for (int entityIndexInChunk = 64; entityIndexInChunk < chunkEntityCount; ++entityIndexInChunk)
                    {
                        if ((mask64 & 1) != 0)
                        {
                            ref var localTransformArrayRef = ref InternalCompilerInterface.UnsafeGetRefToNativeArrayPtrElement<Unity.Transforms.LocalTransform>(localTransformArray, entityIndexInChunk);
                            Execute(in localTransformArrayRef);
                            matchingEntityCount++;
                        }

                        mask64 >>= 1;
                    }
                }
            }
        }

        public void Run() => __ThrowCodeGenException();
        public void RunByRef() => __ThrowCodeGenException();
        public void Run(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
        public void RunByRef(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
        Unity.Jobs.JobHandle __ThrowCodeGenException() => throw new global::System.Exception("This method should have been replaced by source gen.");
        // Emitted to disambiguate scheduling method invocations
        public global::Unity.Jobs.JobHandle Schedule(global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle ScheduleByRef(global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle Schedule(global::Unity.Entities.EntityQuery query, global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle ScheduleByRef(global::Unity.Entities.EntityQuery query, global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
        public void Schedule() => __ThrowCodeGenException();
        public void ScheduleByRef() => __ThrowCodeGenException();
        public void Schedule(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
        public void ScheduleByRef(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle ScheduleParallel(global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle ScheduleParallelByRef(global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle ScheduleParallel(global::Unity.Entities.EntityQuery query, global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle ScheduleParallelByRef(global::Unity.Entities.EntityQuery query, global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle ScheduleParallel(global::Unity.Entities.EntityQuery query, global::Unity.Jobs.JobHandle dependsOn, global::Unity.Collections.NativeArray<int> chunkBaseEntityIndices) => __ThrowCodeGenException();
        public global::Unity.Jobs.JobHandle ScheduleParallelByRef(global::Unity.Entities.EntityQuery query, global::Unity.Jobs.JobHandle dependsOn, global::Unity.Collections.NativeArray<int> chunkBaseEntityIndices) => __ThrowCodeGenException();
        public void ScheduleParallel() => __ThrowCodeGenException();
        public void ScheduleParallelByRef() => __ThrowCodeGenException();
        public void ScheduleParallel(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
        public void ScheduleParallelByRef(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
    }
}

However, when I put the Job inside a class that inherits from SystemBase, the error does not occur.
Code:

using Unity.Collections;
using Unity.Transforms;
using UnityEngine;
using Unity.Entities;

public partial class ErrorExample : SystemBase {
    protected override void OnUpdate()
    {
        throw new System.NotImplementedException();
    }

    [GenerateTestsForBurstCompatibility]
    private partial struct ErrorExampleJob : IJobEntity {
        public void Execute(in LocalTransform localTransfrom) {
            // something here
        }
    }
}

Is this a bug or is it intended behaviour? Thanks!

Misc Info:
Unity: 2022.2.1f1
OS: Windows 10
IDE: Tried both Visual Studio 2022 & VS Code

This is completely expected behavior. The top-level class was not marked as partial. This would mean other declarations of that type aren’t allowed. You need to mark everything in the hierarchy as partial if you want to be able to add a part of some partial nested type.

2 Likes

Thank you for the quick reply. This fixed the issue I had. This is my first time using partial classes/structs so I did not know that was needed