To jest taka sama jak Jason. odpowiedź, ale rozwiązuje niektóre problemy z jego rozwiązaniem.
public static bool IsCastableTo(this Type from, Type to)
{
return to.IsAssignableFrom(from)
|| to.GetConvertOperators().Any(m => m.GetParameters()[0].ParameterType.IsAssignableFrom(from))
|| from.GetConvertOperators(true).Any(m => to.IsAssignableFrom(m.ReturnType));
}
public static IEnumerable<MethodInfo> GetConvertOperators(this Type type, bool lookInBase = false)
{
var bindinFlags = BindingFlags.Public
| BindingFlags.Static
| (lookInBase ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly);
return type.GetMethods(bindinFlags).Where(m => m.Name == "op_Implicit" || m.Name == "op_Explicit");
}
ten powinien radzić sobie w sytuacjach, które powstają na skutek spadków, jak również.Na przykład:
class Mammal { public static implicit operator Car (Mammal o) { return null; } }
class Cow : Mammal { }
class Vehicle { }
class Car : Vehicle { }
tutaj związek ukryte wynosi Mammal
i Car
, ale ponieważ Cow
jest Mammal
również istnieją niejawnego konwersji z Cow
do Car
. Ale wszystkie są Car
s; stąd Cow
może przejść do Vehicle
.
Cow c = null;
Vehicle v = c; //legal
Więc
typeof(Cow).IsCastableTo(typeof(Vehicle)); //true
drukuje prawdziwe, choć nie bezpośredni operator konwersji istnieje między Cow
i Vehicle
.
powyżej rozwiązanie nie dla typów pierwotnych, gdzie konwersja jest wbudowany bezpośrednio w języku niż ramach, więc coś
typeof(short).IsCastableTo(typeof(int));
zawiedzie. Afaik, tylko ręczna obsługa pomoże. Otrzymasz pełną listę konwersji implicit i explicit dla typów liczbowych i other primitive types z msdn.
Edit:
Funkcja IsCastableTo
mógłby być trochę bardziej "DRY" być może kosztem jest mniej czytelny, ale mi się podoba :)
public static bool IsCastableTo(this Type from, Type to)
{
return to.IsAssignableFrom(from)
|| IsCastDefined(to, m => m.GetParameters()[0].ParameterType, _ => from, false)
|| IsCastDefined(from, _ => to, m => m.ReturnType, true);
}
//little irrelevant DRY method
static bool IsCastDefined(Type type, Func<MethodInfo, Type> baseType, Func<MethodInfo, Type> derivedType,
bool lookInBase)
{
var bindinFlags = BindingFlags.Public
| BindingFlags.Static
| (lookInBase ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly);
return type.GetMethods(bindinFlags).Any(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit")
&& baseType(m).IsAssignableFrom(derivedType(m)));
}
Skąd pochodzą te struny? Co próbujesz osiągnąć? – n8wrl