sintaxis - ¿Cómo puedo determinar si existe una conversión implícita en C#?
significado de double en lenguaje c (3)
Tengo dos tipos, T y U, y quiero saber si un operador de conversión implícita se define de T a U.
Soy consciente de la existencia de IsAssignableFrom , y esto no es lo que estoy buscando, ya que no se ocupa de los lanzamientos implícitos.
Un poco de googlear me llevó a esta solución , pero en las propias palabras del autor, este es un código feo (trata de lanzar implícitamente y devuelve falso si hay una excepción, de lo contrario es cierto ...)
Parece que probar la existencia de un método op_Implicit con la firma correcta no funcionará para los tipos primitivos .
¿Existe una forma más limpia de determinar la existencia de un operador de reparto implícito?
Podría usar la reflexión para encontrar el método de conversión implícito para el tipo de destino:
public static bool HasImplicitConversion(Type baseType, Type targetType)
{
return baseType.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType)
.Any(mi => {
ParameterInfo pi = mi.GetParameters().FirstOrDefault();
return pi != null && pi.ParameterType == baseType;
});
}
Puedes usarlo así:
class X {}
class Y
{
public static implicit operator X (Y y)
{
return new X();
}
public static implicit operator Y (X x)
{
return new Y();
}
}
// and then:
bool conversionExists = HasImplicitConversion(typeof(Y), typeof(X));
Tenga en cuenta que esto solo busca una conversión de tipo implícita en el tipo base (el primer tipo pasado). Técnicamente, la conversión de tipo también se puede definir en el otro tipo, por lo que es posible que deba volver a llamar con los tipos invertidos (o incorporarlos en el método). Sin embargo, las conversiones de tipo implícitas pueden no existir en ambos tipos.
Terminé manejando el escenario de tipos primitivos manualmente. No muy elegante, pero funciona.
También he agregado lógica adicional para manejar tipos y enumeraciones anulables.
Reutilizé el código de Poke para el escenario de tipo definido por el usuario.
public class AvailableCastChecker
{
public static bool CanCast(Type from, Type to)
{
if (from.IsAssignableFrom(to))
{
return true;
}
if (HasImplicitConversion(from, from, to)|| HasImplicitConversion(to, from, to))
{
return true;
}
List<Type> list;
if (ImplicitNumericConversions.TryGetValue(from, out list))
{
if (list.Contains(to))
return true;
}
if (to.IsEnum)
{
return CanCast(from, Enum.GetUnderlyingType(to));
}
if (Nullable.GetUnderlyingType(to) != null)
{
return CanCast(from, Nullable.GetUnderlyingType(to));
}
return false;
}
// https://msdn.microsoft.com/en-us/library/y5b434w4.aspx
static Dictionary<Type,List<Type>> ImplicitNumericConversions = new Dictionary<Type, List<Type>>();
static AvailableCastChecker()
{
ImplicitNumericConversions.Add(typeof(sbyte), new List<Type> {typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(byte), new List<Type> { typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(short), new List<Type> { typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(ushort), new List<Type> { typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(int), new List<Type> { typeof(long), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(uint), new List<Type> { typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(long), new List<Type> { typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(char), new List<Type> { typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(float), new List<Type> { typeof(double) });
ImplicitNumericConversions.Add(typeof(ulong), new List<Type> { typeof(float), typeof(double), typeof(decimal) });
}
static bool HasImplicitConversion(Type definedOn, Type baseType, Type targetType)
{
return definedOn.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType)
.Any(mi =>
{
ParameterInfo pi = mi.GetParameters().FirstOrDefault();
return pi != null && pi.ParameterType == baseType;
});
}
}
Here''s una solución que encontré. El código principal se muestra a continuación (después de una traducción simple):
public static bool IsImplicitFrom(this Type type, Type fromType) {
if (type == null || fromType == null) {
return false;
}
// support for reference type
if (type.IsByRef) { type = type.GetElementType(); }
if (fromType.IsByRef) { fromType = type.GetElementType(); }
// could always be convert to object
if (type.Equals(typeof(object))) {
return true;
}
// check if it could be convert using standard implicit cast
if (IsStandardImplicitFrom(type, fromType)) {
return true;
}
// determine implicit convert operator
Type nonNullalbeType, nonNullableFromType;
if (IsNullableType(type, out nonNullalbeType) &&
IsNullableType(fromType, out nonNullableFromType)) {
type = nonNullalbeType;
fromType = nonNullableFromType;
}
return ConversionCache.GetImplicitConversion(fromType, type) != null;
}
internal static bool IsStandardImplicitFrom(this Type type, Type fromType) {
// support for Nullable<T>
if (!type.IsValueType || IsNullableType(ref type)) {
fromType = GetNonNullableType(fromType);
}
// determine implicit value type convert
HashSet<TypeCode> typeSet;
if (!type.IsEnum &&
ImplicitNumericConversions.TryGetValue(Type.GetTypeCode(type), out typeSet)) {
if (!fromType.IsEnum && typeSet.Contains(Type.GetTypeCode(fromType))) {
return true;
}
}
// determine implicit reference type convert and boxing convert
return type.IsAssignableFrom(fromType);
}
Actualización: linked el archivo completo.