friflo / Friflo.Json.Fliox

C# ECS + ORM
https://github.com/friflo/Friflo.Engine.ECS
GNU Lesser General Public License v3.0
165 stars 12 forks source link

Generic components and tags types are not supported and throw exception on usage. #53

Closed friflo closed 3 months ago

friflo commented 3 months ago

The issue came up in: https://github.com/friflo/Friflo.Json.Fliox/issues/51#issuecomment-2176902166

Generic component and tags type are not supported in library version <= 2.0.0. E.g.

public struct GenericComponent<T> : IComponent {
    public T Value;
}

public struct GenericTag<T> : ITag { }

These types are not registered as component / tag type and throw an exception when using them.

System.TypeInitializationException : The type initializer for 'Friflo.Engine.ECS.TagInfo`1' threw an exception.
  ----> System.Collections.Generic.KeyNotFoundException : The given key 'Tests.ECS.GenericTag`1[System.Int32]' was not present in the dictionary.
   at Friflo.Engine.ECS.Tags.Get[T]() 
   at Friflo.Engine.ECS.Entity.AddTag[TTag]()
   at Tests.ECS.Base.Test_Components.Test_Generic_Component()
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
--KeyNotFoundException
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Friflo.Engine.ECS.SchemaTypeUtils.GetTagIndex(Type type)
   at Friflo.Engine.ECS.TagInfo`1..cctor()
friflo commented 3 months ago

My plan to support generic component / tag types: An attribute needs to be added to those types. E,g,

[GenericInstanceType("comp-int", typeof(int))]       // register  GenericComponent<int>
public struct GenericComponent<T> : IComponent {
    public T Value;
}

[GenericInstanceType("tag-int",    typeof(int))]     // register  GenericTag<int>
[GenericInstanceType("tag-string", typeof(string))]  // register  GenericTag<string>
public struct GenericTag<T> : ITag { }

Note: The first paramater e.g. "comp-int" is they key used for JSON serialization.

I guess I will finish this today an publish a nuget package.

friflo commented 3 months ago

Just published package 2.1.0 supporting Generic components and tags types on nuget. These type must be annotated with [GenericInstanceType(...)] as shown in the example above.

In case of a missing attribute an exception is thrown like:

System.TypeInitializationException : The type initializer for 'Friflo.Engine.ECS.TagInfo`1' threw an exception.
  ----> System.InvalidOperationException : Missing attribute [GenericInstanceType("<key>", typeof(Int32), typeof(String))] for generic ITag type: Tests.ECS.GenericTag2`2[System.Int32,System.String]
   at Friflo.Engine.ECS.Tags.Get[T]() 
   at Friflo.Engine.ECS.Entity.AddTag[TTag]()
   at Tests.ECS.Base.Test_Components.Test_Generic_Component_exceptions()
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
--InvalidOperationException
   at Friflo.Engine.ECS.SchemaTypeUtils.GetTagIndex(Type type)
   at Friflo.Engine.ECS.TagInfo`1..cctor()

The inner exception describes how to fix the issue:

System.InvalidOperationException : Missing attribute [GenericInstanceType("<key>", typeof(Int32), typeof(String))] for generic ITag type: Tests.ECS.GenericTag2`2[System.Int32,System.String]
friflo commented 3 months ago

Note I would not advocate to use generic component & tag types. Component & tag types should be as simple as possible. Making them generic adds a layer of abstraction. They are more complicated in usage and understanding.

Beside this their performance and memory characteristics are same as non generic types.