I'm trying to make a generic Mediator system, and want to allow messages with implicit operators to receive messages even if their respective type T is not provided.
This is where things are breaking, and I don't understand. Hoping someone smarter than me will.
public static class Mediator
{
private static Dictionary<string, HashSet<Type>> m_typedMessages =
new Dictionary<string, HashSet<Type>>();
public static void NotifySubscribers<T>(string a_message, T a_arg, bool a_holdMessage = false)
{
TryAddTypedMessage(a_message, typeof(T));
foreach (Type type in m_typedMessages[a_message])
{
if (type == typeof(T) || HasImplicitConversion(type, typeof(T)))
{
Type thisType = typeof(Catalogue<>).MakeGenericType(new Type[] { type });
MethodInfo typedMethod = thisType.GetMethod("NotifySubscribers");
typedMethod.Invoke(null, new object[] { a_message, a_arg, a_holdMessage });
}
}
}
private static bool HasImplicitConversion(Type a_baseType, Type a_targetType)
{
MethodInfo[] methods = a_baseType.GetMethods(BindingFlags.Public | BindingFlags.Static);
IEnumerable<MethodInfo> implicitCasts = methods.Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == a_baseType);
bool hasMatchingCast = implicitCasts.Any(mi =>
{
ParameterInfo pi = mi.GetParameters().FirstOrDefault();
return pi != null && pi.ParameterType == a_targetType;
});
return hasMatchingCast;
}
HasImplicitConversion works fine. For my test, I have a class I made a class called ColorData, and it looks like this:
public class ColorData
{
public float r, g, b, a;
public static implicit operator ColorData(float a_float)
{
ColorData cd = new ColorData
{
r = a_float,
g = 2f * a_float,
b = a_float / 3f,
a = 1f
};
return cd;
}
}
It all goes good, and it passes all the checks until it gets to the typedMethod.Invoke, where despite having a implicit cast from float to ColorData, it still throws this:
ArgumentException: Object of type 'System.Single' cannot be converted to type 'SubTestUI+ColorData'. System.RuntimeType.CheckValue (System.Object value, System.Reflection.Binder binder, System.Globalization.CultureInfo culture, System.Reflection.BindingFlags invokeAttr) (at <1f0c1ef1ad524c38bbc5536809c46b48>:0) System.Reflection.MonoMethod.ConvertValues (System.Reflection.Binder binder, System.Object[] args, System.Reflection.ParameterInfo[] pinfo, System.Globalization.CultureInfo culture, System.Reflection.BindingFlags invokeAttr) (at <1f0c1ef1ad524c38bbc5536809c46b48>:0) System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <1f0c1ef1ad524c38bbc5536809c46b48>:0) System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at <1f0c1ef1ad524c38bbc5536809c46b48>:0) Mouledoux.Mediation.Systems.Mediator.NotifySubscribers[T] (System.String a_message, T a_arg, System.Boolean a_holdMessage)
I assume it's because I still just pass a_arg as a type T when I call invoke, but shouldn't having an implicit operation just allow it to go through? I can't cast it to type 'type' which in this case IS ColorData at the time the error happens, but I can't cast a_arg as a Type. Any help at all appreciated.