Wie überprüfe ich die Zuweisbarkeit von Typen zur Laufzeit in C#?

Wie überprüfe ich die Zuweisbarkeit von Typen zur Laufzeit in C#?

Eigentlich sind es drei Möglichkeiten, wie ein Typ einem anderen in dem von Ihnen gesuchten Sinne „zuweisbar“ sein kann.

  • Klassenhierarchie, Schnittstellenimplementierung, Kovarianz und Kontravarianz. Das ist was .IsAssignableFrom sucht schon nach. (Dazu gehören auch zulässige Boxoperationen, z. B. int bis object oder DateTime bis ValueType .)

  • Benutzerdefinierte implizite Konvertierungen. Darauf beziehen sich alle anderen Antworten. Diese können Sie über Reflection abrufen, beispielsweise die implizite Konvertierung von int bis decimal ist eine statische Methode, die so aussieht:

    System.Decimal op_Implicit(Int32)
    

    Sie müssen nur die beiden relevanten Typen (in diesem Fall Int32 und Decimal ); Wenn die Konvertierung nicht darin enthalten ist, existiert sie nicht.

  • Integrierte implizite Konvertierungen, die in der C#-Sprachspezifikation definiert sind. Leider zeigt Reflection diese nicht an. Sie müssen sie in der Spezifikation finden und die Zuweisungsregeln manuell in Ihren Code kopieren. Dazu gehören numerische Konvertierungen, z. int bis long sowie float bis double , Zeigerkonvertierungen, Nullable-Konvertierungen (int bis int? ) und mehr Conversions.

Darüber hinaus kann eine benutzerdefinierte implizite Konvertierung mit einer integrierten impliziten Konvertierung verkettet werden. Zum Beispiel, wenn eine benutzerdefinierte implizite Konvertierung von int existiert zu einem Typ T , dann dient es auch als Konvertierung von short bis T . Ebenso T bis short verdoppelt sich als T bis int .


Dieser fast funktioniert ... es verwendet Linq-Ausdrücke:

public static bool IsReallyAssignableFrom(this Type type, Type otherType)
{
    if (type.IsAssignableFrom(otherType))
        return true;

    try
    {
        var v = Expression.Variable(otherType);
        var expr = Expression.Convert(v, type);
        return expr.Method == null || expr.Method.Name == "op_Implicit";
    }
    catch(InvalidOperationException ex)
    {
        return false;
    }
}

Der einzige Fall, der nicht funktioniert, sind eingebaute Konvertierungen für primitive Typen:Es wird fälschlicherweise true zurückgegeben für Konvertierungen, die explizit sein sollen (z. B. int bis short ). Ich schätze, Sie könnten diese Fälle manuell handhaben, da es eine endliche (und ziemlich kleine) Anzahl von ihnen gibt.

Ich mag es nicht wirklich, eine Ausnahme abfangen zu müssen, um ungültige Conversions zu erkennen, aber ich sehe keine andere einfache Möglichkeit, dies zu tun ...