Browse Source

Merge pull request #55563 from raulsntos/csharp-delegates-for-generic-class

Fix C# `get_all_delegates` method for generic classes
Ignacio Roldán Etcheverry 3 years ago
parent
commit
2a9dd654bc

+ 12 - 0
modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs

@@ -79,6 +79,18 @@ namespace Godot
         /// </exception>
         /// </exception>
         private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
         private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
 
 
+        /// <summary>
+        /// Returns the generic type definition of <paramref name="type"/>.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">
+        /// Thrown when the given <paramref name="type"/> is not a generic type.
+        /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
+        /// </exception>
+        private static void GetGenericTypeDefinition(Type type, out Type genericTypeDefinition)
+        {
+            genericTypeDefinition = type.GetGenericTypeDefinition();
+        }
+
         /// <summary>
         /// <summary>
         /// Gets the element type for the given <paramref name="arrayType"/>.
         /// Gets the element type for the given <paramref name="arrayType"/>.
         /// </summary>
         /// </summary>

+ 4 - 0
modules/mono/mono_gd/gd_mono_cache.cpp

@@ -177,6 +177,8 @@ void CachedData::clear_godot_api_cache() {
 	methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
 	methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
 	methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
 	methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
 
 
+	methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();
+
 	methodthunk_MarshalUtils_ArrayGetElementType.nullify();
 	methodthunk_MarshalUtils_ArrayGetElementType.nullify();
 	methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();
 	methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();
 
 
@@ -299,6 +301,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, 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, 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, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2));
 	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3));
 	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3));
 
 

+ 2 - 0
modules/mono/mono_gd/gd_mono_cache.h

@@ -148,6 +148,8 @@ struct CachedData {
 	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
 	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
 	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
 	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
 
 
+	GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;
+
 	GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
 	GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
 	GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
 	GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
 
 

+ 10 - 1
modules/mono/mono_gd/gd_mono_class.cpp

@@ -464,9 +464,18 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
 		return delegates_list;
 		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 = nullptr;
 	void *iter = nullptr;
 	MonoClass *raw_class = nullptr;
 	MonoClass *raw_class = nullptr;
-	while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != nullptr) {
+	while ((raw_class = mono_class_get_nested_types(klass, &iter)) != nullptr) {
 		if (mono_class_is_delegate(raw_class)) {
 		if (mono_class_is_delegate(raw_class)) {
 			StringName name = String::utf8(mono_class_get_name(raw_class));
 			StringName name = String::utf8(mono_class_get_name(raw_class));
 
 

+ 6 - 0
modules/mono/mono_gd/gd_mono_utils.cpp

@@ -614,6 +614,12 @@ bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
 	return (bool)res;
 	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) {
 void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
 	MonoException *exc = nullptr;
 	MonoException *exc = nullptr;
 	CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);
 	CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);

+ 2 - 0
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_icollection(MonoReflectionType *p_reftype);
 bool type_is_generic_idictionary(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 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);
 void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);