Просмотр исходного кода

Merge pull request #34750 from neikeq/issue-18969

Mono/C#: Make 'GD.Print' and its variants fallback to 'ToString()'
Rémi Verschelde 5 лет назад
Родитель
Сommit
1c88ee6c96

+ 81 - 15
modules/mono/glue/gd_glue.cpp

@@ -71,48 +71,114 @@ MonoObject *godot_icall_GD_instance_from_id(uint64_t p_instance_id) {
 }
 
 void godot_icall_GD_print(MonoArray *p_what) {
-	Array what = GDMonoMarshal::mono_array_to_Array(p_what);
 	String str;
-	for (int i = 0; i < what.size(); i++)
-		str += what[i].operator String();
+	int length = mono_array_length(p_what);
+
+	for (int i = 0; i < length; i++) {
+		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+		MonoException *exc = NULL;
+		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+		if (exc) {
+			GDMonoUtils::set_pending_exception(exc);
+			return;
+		}
+
+		str += elem_str;
+	}
+
 	print_line(str);
 }
 
 void godot_icall_GD_printerr(MonoArray *p_what) {
-	Array what = GDMonoMarshal::mono_array_to_Array(p_what);
+
 	String str;
-	for (int i = 0; i < what.size(); i++)
-		str += what[i].operator String();
+	int length = mono_array_length(p_what);
+
+	for (int i = 0; i < length; i++) {
+		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+		MonoException *exc = NULL;
+		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+		if (exc) {
+			GDMonoUtils::set_pending_exception(exc);
+			return;
+		}
+
+		str += elem_str;
+	}
+
 	print_error(str);
 }
 
 void godot_icall_GD_printraw(MonoArray *p_what) {
-	Array what = GDMonoMarshal::mono_array_to_Array(p_what);
 	String str;
-	for (int i = 0; i < what.size(); i++)
-		str += what[i].operator String();
+	int length = mono_array_length(p_what);
+
+	for (int i = 0; i < length; i++) {
+		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+		MonoException *exc = NULL;
+		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+		if (exc) {
+			GDMonoUtils::set_pending_exception(exc);
+			return;
+		}
+
+		str += elem_str;
+	}
+
 	OS::get_singleton()->print("%s", str.utf8().get_data());
 }
 
 void godot_icall_GD_prints(MonoArray *p_what) {
-	Array what = GDMonoMarshal::mono_array_to_Array(p_what);
 	String str;
-	for (int i = 0; i < what.size(); i++) {
+	int length = mono_array_length(p_what);
+
+	for (int i = 0; i < length; i++) {
+		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+		MonoException *exc = NULL;
+		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+		if (exc) {
+			GDMonoUtils::set_pending_exception(exc);
+			return;
+		}
+
 		if (i)
 			str += " ";
-		str += what[i].operator String();
+
+		str += elem_str;
 	}
+
 	print_line(str);
 }
 
 void godot_icall_GD_printt(MonoArray *p_what) {
-	Array what = GDMonoMarshal::mono_array_to_Array(p_what);
 	String str;
-	for (int i = 0; i < what.size(); i++) {
+	int length = mono_array_length(p_what);
+
+	for (int i = 0; i < length; i++) {
+		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+		MonoException *exc = NULL;
+		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+		if (exc) {
+			GDMonoUtils::set_pending_exception(exc);
+			return;
+		}
+
 		if (i)
 			str += "\t";
-		str += what[i].operator String();
+
+		str += elem_str;
 	}
+
 	print_line(str);
 }
 

+ 66 - 18
modules/mono/mono_gd/gd_mono_marshal.cpp

@@ -700,15 +700,11 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 								 p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
 }
 
-Variant mono_object_to_variant(MonoObject *p_obj) {
-	if (!p_obj)
-		return Variant();
+Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) {
 
-	ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
-
-	ERR_FAIL_COND_V(!type.type_class, Variant());
+	ERR_FAIL_COND_V(!p_type.type_class, Variant());
 
-	switch (type.type_encoding) {
+	switch (p_type.type_encoding) {
 		case MONO_TYPE_BOOLEAN:
 			return (bool)unbox<MonoBoolean>(p_obj);
 
@@ -745,7 +741,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 		} break;
 
 		case MONO_TYPE_VALUETYPE: {
-			GDMonoClass *vtclass = type.type_class;
+			GDMonoClass *vtclass = p_type.type_class;
 
 			if (vtclass == CACHED_CLASS(Vector2))
 				return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj));
@@ -783,7 +779,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 
 		case MONO_TYPE_ARRAY:
 		case MONO_TYPE_SZARRAY: {
-			MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
+			MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
 
 			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
 				return mono_array_to_Array((MonoArray *)p_obj);
@@ -809,11 +805,15 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 			if (array_type->eklass == CACHED_CLASS_RAW(Color))
 				return mono_array_to_PoolColorArray((MonoArray *)p_obj);
 
-			ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant.");
+			if (p_fail_with_err) {
+				ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant.");
+			} else {
+				return Variant();
+			}
 		} break;
 
 		case MONO_TYPE_CLASS: {
-			GDMonoClass *type_class = type.type_class;
+			GDMonoClass *type_class = p_type.type_class;
 
 			// GodotObject
 			if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
@@ -871,18 +871,18 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 		} break;
 
 		case MONO_TYPE_GENERICINST: {
-			MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type());
+			MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
 
 			if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
 				MonoException *exc = NULL;
-				MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
+				MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
 				UNHANDLED_EXCEPTION(exc);
 				return *unbox<Dictionary *>(ret);
 			}
 
 			if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
 				MonoException *exc = NULL;
-				MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
+				MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
 				UNHANDLED_EXCEPTION(exc);
 				return *unbox<Array *>(ret);
 			}
@@ -893,7 +893,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 				return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj);
 			}
 
-			if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+			if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
 				return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj);
 			}
 
@@ -901,14 +901,62 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 				return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
 			}
 
-			if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+			if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
 				return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
 			}
 		} break;
 	}
 
-	ERR_FAIL_V_MSG(Variant(), "Attempted to convert an unmarshallable managed type to Variant. Name: '" +
-									  type.type_class->get_name() + "' Encoding: " + itos(type.type_encoding) + ".");
+	if (p_fail_with_err) {
+		ERR_FAIL_V_MSG(Variant(), "Attempted to convert an unmarshallable managed type to Variant. Name: '" +
+										  p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
+	} else {
+		return Variant();
+	}
+}
+
+Variant mono_object_to_variant(MonoObject *p_obj) {
+	if (!p_obj)
+		return Variant();
+
+	ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
+
+	return mono_object_to_variant_impl(p_obj, type);
+}
+
+Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
+	if (!p_obj)
+		return Variant();
+
+	return mono_object_to_variant_impl(p_obj, p_type);
+}
+
+Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type) {
+	if (!p_obj)
+		return Variant();
+
+	return mono_object_to_variant_impl(p_obj, p_type, /* fail_with_err: */ false);
+}
+
+String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
+	ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
+	Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type);
+
+	if (var.get_type() == Variant::NIL && p_obj != NULL) {
+		// Cannot convert MonoObject* to Variant; fallback to 'ToString()'.
+		MonoException *exc = NULL;
+		MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc);
+
+		if (exc) {
+			if (r_exc)
+				*r_exc = exc;
+			return String();
+		}
+
+		return GDMonoMarshal::mono_string_to_godot(mono_str);
+	} else {
+		return var.operator String();
+	}
 }
 
 MonoArray *Array_to_mono_array(const Array &p_array) {

+ 6 - 0
modules/mono/mono_gd/gd_mono_marshal.h

@@ -115,6 +115,12 @@ _FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const Ma
 }
 
 Variant mono_object_to_variant(MonoObject *p_obj);
+Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type);
+Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type);
+
+/// Tries to convert the MonoObject* to Variant and then convert the Variant to String.
+/// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead.
+String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc);
 
 // Array