Genesis
Genesis copied to clipboard
[BUG] Add try-catch to ReflectionTools to suppress ReflectionTypeLoadException
Describe the bug
Encounter this error when click on a GenesisSettings asset
ReflectionTypeLoadException: Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown.
System.Reflection.Assembly.GetTypes () (at <695d1cc93cca45069c528c15c9fdd749>:0)
Genesis.Shared.ReflectionTools.GetAllImplementingInstancesOfInterface[T] () (at /home/runner/work/Genesis/Genesis/Genesis/ExternalApp/Genesis.Shared/Tools/ReflectionTools.cs:319)
JCMG.Genesis.Editor.Inspectors.GenesisSettingsInspector..cctor () (at Library/PackageCache/[email protected]/Scripts/Editor/Inspectors/GenesisSettingsInspector.cs:43)
Rethrow as TypeInitializationException: The type initializer for 'JCMG.Genesis.Editor.Inspectors.GenesisSettingsInspector' threw an exception.
UnityEditor.UIElements.InspectorElement+<>c__DisplayClass59_0.<CreateIMGUIInspectorFromEditor>b__0 () (at <1ada6c7052bb42378c5ec1bd01fc4723>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)
Unity Version: Unity 2020.3.20f1 Genesis is installed via OpenUPM
To Reproduce This is currently a private project so I cannot share steps to reproduce, but I can describe a bit:
- I created a plugin to generate some "union" structs defined by this attribute
[Union(typeof((<...tuple syntax...>)))] - The user codes in Unity are placed inside a folder with an asmdef (
Game.Runtime.asmdef) For example:
namespace Game.Runtime
{
public partial class TestBehaviour : MonoBehaviour
{
public partial class Container
{
[Union(typeof((Vector2, MySpecialStruct)))]
public readonly partial struct ExampleUnion
{
}
}
}
public struct MySpecialStruct
{
public event Action OnClick;
public float X { get; }
public int Y;
}
}
- Then press "Generate" button on the
GenesisSettingsand we will have this code:
namespace Game.Runtime
{
partial class TestBehaviour {
partial class Container {
[StructLayout(LayoutKind.Explicit, Pack = 1)]
partial struct ExampleUnion
{
[FieldOffset(0)]
private readonly UnityEngine.Vector2 _Item1;
[FieldOffset(0)]
private readonly Game.Runtime.MySpecialStruct _Item2;
}
}
}
}
- After step 3, whenever I clicked on a
GenesisSettingsasset, it would throwReflectionTypeLoadException. - If I replace
MySpecialStructin the Union attribute withfloatorVector3, no exception will occur.
Expected behavior
ReflectionTypeLoadException should be suppress in ReflectionTools.cs
Hi @laicasaane , I just wanted to give you a heads up that I did see this and will be following up this weekend to go through this and the associated fix.
@laicasaane What is the definition of the Union attribute in this case? Attempting to reproduce this locally has been a bit difficult without knowing what the constructor param typeof((Vector2, MySpecialStruct) resolves to.
@jeffcampbellmakesgames This is the usage of Union attribute
Usage:
using UnityEngine;
using ZBase.Common.Unions;
namespace Examples
{
public partial class ExampleBehaviour : MonoBehaviour
{
[Union(typeof((int, float)))]
public readonly partial struct ExampleUnionA { }
}
}
Generated code:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool (Genesis v2.3.2.0).
//
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
using ZBase.Common.Unions;
namespace Examples
{
partial class ExampleBehaviour {
[StructLayout(LayoutKind.Explicit, Pack = 1)]
partial struct ExampleUnionA : IUnion, IEquatable<ExampleUnionA>
{
public enum Fields : byte
{
Item1,
Item2,
}
[FieldOffset(0)]
public readonly Fields Field;
[FieldOffset(1)]
public readonly int Item1;
[FieldOffset(1)]
public readonly float Item2;
public ExampleUnionA(int value)
{
Field = Fields.Item1;
Item2 = default;
Item1 = value;
}
public ExampleUnionA(in int value)
{
Field = Fields.Item1;
Item2 = default;
Item1 = value;
}
public ExampleUnionA(float value)
{
Field = Fields.Item2;
Item1 = default;
Item2 = value;
}
public ExampleUnionA(in float value)
{
Field = Fields.Item2;
Item1 = default;
Item2 = value;
}
public ExampleUnionA(Fields type)
{
Field = type;
Item1 = default;
Item2 = default;
}
public bool TryGet(out int value)
{
if (Field != Fields.Item1)
{
value = default;
return false;
}
value = Item1;
return true;
}
public bool TryGet(out float value)
{
if (Field != Fields.Item2)
{
value = default;
return false;
}
value = Item2;
return true;
}
public System.Type GetUnderlyingType()
{
if (Field == Fields.Item1)
return Item1.GetType();
if (Field == Fields.Item2)
return Item2.GetType();
return GetType();
}
public override int GetHashCode()
{
var hash = new HashCode();
hash.Add(Field);
if (Field == Fields.Item1)
hash.Add(Item1);
if (Field == Fields.Item2)
hash.Add(Item2);
return hash.ToHashCode();
}
public override bool Equals(object obj)
=> obj is ExampleUnionA other && Equals(this, other);
public bool Equals(ExampleUnionA other)
=> Equals(this, other);
public static bool Equals(ExampleUnionA a, ExampleUnionA b)
{
if (a.Field != b.Field)
return false;
if (a.Field == Fields.Item1)
return a.Item1 == b.Item1;
if (a.Field == Fields.Item2)
return a.Item2 == b.Item2;
return false;
}
public static bool operator ==(ExampleUnionA left, ExampleUnionA right)
=> Equals(left, right);
public static bool operator !=(ExampleUnionA left, ExampleUnionA right)
=> !Equals(left, right);
public bool Equals(in ExampleUnionA other)
=> Equals(in this, in other);
public static bool Equals(in ExampleUnionA a, in ExampleUnionA b)
{
if (a.Field != b.Field)
return false;
if (a.Field == Fields.Item1)
return a.Item1 == b.Item1;
if (a.Field == Fields.Item2)
return a.Item2 == b.Item2;
return false;
}
public static bool operator ==(in ExampleUnionA left, in ExampleUnionA right)
=> Equals(in left, in right);
public static bool operator !=(in ExampleUnionA left, in ExampleUnionA right)
=> !Equals(in left, in right);
public override string ToString()
{
if (Field == Fields.Item1)
return Item1.ToString();
if (Field == Fields.Item2)
return Item2.ToString();
return string.Empty;
}
public static implicit operator ExampleUnionA(int value)
=> new ExampleUnionA(value);
public static implicit operator int(ExampleUnionA value)
=> value.Item1;
public static implicit operator ExampleUnionA(float value)
=> new ExampleUnionA(value);
public static implicit operator float(ExampleUnionA value)
=> value.Item2;
}
}
}