确定是否可以将reflection类型强制转换为另一种reflection类型

在.net(C#)中,如果通过reflection发现了两种类型,是否可以确定是否可以将其转换为另一种? (隐式和/或显式)。

我要做的是创建一个库,允许用户指定一种类型的属性映射到另一种类型的属性。 如果两个属性具有匹配类型,一切都很好,但我希望能够允许它们映射隐式/显式转换可用的属性。 所以,如果他们有

class from { public int IntProp{get;set;} } class to { public long LongProp{get;set;} public DateTime DateTimeProp{get;set;} } 

他们可以说from.IntProp将被分配到.LongProp(作为一个隐形演员存在)。 但如果他们说它映射到DateTimeProp我就能确定没有可用的强制转换并抛出exception。

 public static bool HasConversionOperator( Type from, Type to ) { Func bodyFunction = body => Expression.Convert( body, to ); ParameterExpression inp = Expression.Parameter( from, "inp" ); try { // If this succeeds then we can cast 'from' type to 'to' type using implicit coercion Expression.Lambda( bodyFunction( inp ), inp ).Compile(); return true; } catch( InvalidOperationException ) { return false; } } 

这应该是隐式和显式转换的技巧(包括数字类型,类等)

这里的实现并不漂亮,但我认为它涵盖了所有情况(隐式/显式运算符,可空的装箱/拆箱,基本类型转换,标准转换)。 请注意,说转换可能成功与成功之间存在差异(这几乎不可能确定)。 有关详细信息,全面的unit testing和隐式版本,请查看我的post。

 public static bool IsCastableTo(this Type from, Type to) { // from http://www.codeducky.org/10-utilities-c-developers-should-know-part-one/ Throw.IfNull(from, "from"); Throw.IfNull(to, "to"); // explicit conversion always works if to : from OR if // there's an implicit conversion if (from.IsAssignableFrom(to) || from.IsImplicitlyCastableTo(to)) { return true; } // for nullable types, we can simply strip off the nullability and evaluate the underyling types var underlyingFrom = Nullable.GetUnderlyingType(from); var underlyingTo = Nullable.GetUnderlyingType(to); if (underlyingFrom != null || underlyingTo != null) { return (underlyingFrom ?? from).IsCastableTo(underlyingTo ?? to); } if (from.IsValueType) { try { ReflectionHelpers.GetMethod(() => AttemptExplicitCast()) .GetGenericMethodDefinition() .MakeGenericMethod(from, to) .Invoke(null, new object[0]); return true; } catch (TargetInvocationException ex) { return !( ex.InnerException is RuntimeBinderException // if the code runs in an environment where this message is localized, we could attempt a known failure first and base the regex on it's message && Regex.IsMatch(ex.InnerException.Message, @"^Cannot convert type '.*' to '.*'$") ); } } else { // if the from type is null, the dynamic logic above won't be of any help because // either both types are nullable and thus a runtime cast of null => null will // succeed OR we get a runtime failure related to the inability to cast null to // the desired type, which may or may not indicate an actual issue. thus, we do // the work manually return from.IsNonValueTypeExplicitlyCastableTo(to); } } private static bool IsNonValueTypeExplicitlyCastableTo(this Type from, Type to) { if ((to.IsInterface && !from.IsSealed) || (from.IsInterface && !to.IsSealed)) { // any non-sealed type can be cast to any interface since the runtime type MIGHT implement // that interface. The reverse is also true; we can cast to any non-sealed type from any interface // since the runtime type that implements the interface might be a derived type of to. return true; } // arrays are complex because of array covariance // (see http://msmvps.com/blogs/jon_skeet/archive/2013/06/22/array-covariance-not-just-ugly-but-slow-too.aspx). // Thus, we have to allow for things like var x = (IEnumerable)new object[0]; // and var x = (object[])default(IEnumerable); var arrayType = from.IsArray && !from.GetElementType().IsValueType ? from : to.IsArray && !to.GetElementType().IsValueType ? to : null; if (arrayType != null) { var genericInterfaceType = from.IsInterface && from.IsGenericType ? from : to.IsInterface && to.IsGenericType ? to : null; if (genericInterfaceType != null) { return arrayType.GetInterfaces() .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericInterfaceType.GetGenericTypeDefinition() && i.GetGenericArguments().Zip(to.GetGenericArguments(), (ia, ta) => ta.IsAssignableFrom(ia) || ia.IsAssignableFrom(ta)).All(b => b)); } } // look for conversion operators. Even though we already checked for implicit conversions, we have to look // for operators of both types because, for example, if a class defines an implicit conversion to int then it can be explicitly // cast to uint const BindingFlags conversionFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy; var conversionMethods = from.GetMethods(conversionFlags) .Concat(to.GetMethods(conversionFlags)) .Where(m => (m.Name == "op_Explicit" || m.Name == "op_Implicit") && m.Attributes.HasFlag(MethodAttributes.SpecialName) && m.GetParameters().Length == 1 && ( // the from argument of the conversion function can be an indirect match to from in // either direction. For example, if we have A : B and Foo defines a conversion from B => Foo, // then C# allows A to be cast to Foo m.GetParameters()[0].ParameterType.IsAssignableFrom(from) || from.IsAssignableFrom(m.GetParameters()[0].ParameterType) ) ); if (to.IsPrimitive && typeof(IConvertible).IsAssignableFrom(to)) { // as mentioned above, primitive convertible types (ie not IntPtr) get special // treatment in the sense that if you can convert from Foo => int, you can convert // from Foo => double as well return conversionMethods.Any(m => m.ReturnType.IsCastableTo(to)); } return conversionMethods.Any(m => m.ReturnType == to); } private static void AttemptExplicitCast() { // based on the IL generated from // var x = (TTo)(dynamic)default(TFrom); var binder = Microsoft.CSharp.RuntimeBinder.Binder.Convert(CSharpBinderFlags.ConvertExplicit, typeof(TTo), typeof(TypeHelpers)); var callSite = CallSite>.Create(binder); callSite.Target(callSite, default(TFrom)); } 

调查TypeConverter会更好。

直接回答你的问题……

如果您通过reflection发现了两种类型,则可以确定是否可以将一种类型转换为另一种类型? (隐式和/或显式)

…你可以使用类似的东西:

 to.GetType().IsAssignableFrom(from.GetType()); 

Type.IsAssignableFrom()方法可以完全用于您的目的。 与使用TypeConverters相比,这也会相当简单(即使只是稍微提高性能)。

所以,可能你的意思是鸭子打字或结构打字? 有几种实现可以动态生成所需的代理。

例如:

http://www.deftflux.net/blog/page/Duck-Typing-Project.aspx