diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs index 3051bcedc78..ee4d0eed08e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs @@ -79,6 +79,18 @@ namespace Godot /// private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>); + /// + /// Returns the generic type definition of . + /// + /// + /// Thrown when the given is not a generic type. + /// That is, returns . + /// + private static void GetGenericTypeDefinition(Type type, out Type genericTypeDefinition) + { + genericTypeDefinition = type.GetGenericTypeDefinition(); + } + /// /// Gets the element type for the given . /// diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index c7677d044c0..1294b001d70 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -167,6 +167,8 @@ void CachedData::clear_godot_api_cache() { methodthunk_MarshalUtils_TypeIsGenericICollection.nullify(); methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify(); + methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify(); + methodthunk_MarshalUtils_ArrayGetElementType.nullify(); methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify(); @@ -279,6 +281,8 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3)); diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index fae0d55dc8f..d775e56e9b2 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -138,6 +138,8 @@ struct CachedData { GDMonoMethodThunkR methodthunk_MarshalUtils_TypeIsGenericICollection; GDMonoMethodThunkR methodthunk_MarshalUtils_TypeIsGenericIDictionary; + GDMonoMethodThunk methodthunk_MarshalUtils_GetGenericTypeDefinition; + GDMonoMethodThunk methodthunk_MarshalUtils_ArrayGetElementType; GDMonoMethodThunk methodthunk_MarshalUtils_DictionaryGetKeyValueTypes; diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index d0cb7162ee0..df715983fae 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -438,12 +438,22 @@ const Vector &GDMonoClass::get_all_properties() { } const Vector &GDMonoClass::get_all_delegates() { - if (delegates_fetched) + if (delegates_fetched) { return delegates_list; + } + + // If the class is generic we must use the generic type definition. + MonoClass *klass = mono_class; + if (mono_type_get_type(get_mono_type()) == MONO_TYPE_GENERICINST) { + MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), get_mono_type()); + GDMonoUtils::Marshal::get_generic_type_definition(reftype, &reftype); + MonoType *type = mono_reflection_type_get_type(reftype); + klass = mono_class_from_mono_type(type); + } void *iter = NULL; MonoClass *raw_class = NULL; - while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != NULL) { + while ((raw_class = mono_class_get_nested_types(klass, &iter)) != NULL) { if (mono_class_is_delegate(raw_class)) { StringName name = String::utf8(mono_class_get_name(raw_class)); diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 1552b70bd01..63c7de0e35c 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -587,6 +587,12 @@ bool type_is_generic_idictionary(MonoReflectionType *p_reftype) { return (bool)res; } +void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) { + MonoException *exc = nullptr; + CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc); + UNHANDLED_EXCEPTION(exc); +} + void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) { MonoException *exc = NULL; CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 5a0c36d6390..22998f54e1d 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -62,6 +62,8 @@ bool type_is_generic_ienumerable(MonoReflectionType *p_reftype); bool type_is_generic_icollection(MonoReflectionType *p_reftype); bool type_is_generic_idictionary(MonoReflectionType *p_reftype); +void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype); + void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype); void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);