检查类型是否为可转换/子类

use*_*974 16 c#

我有两个成员类型作为字符串 - 而不是类型实例.如何检查这两种类型是否可浇铸?假设字符串1是"System.Windows.Forms.Label",另一个是"System.Windows.Forms.Control".如何检查第一个是否是第二个的子类(或隐式可转换)?这是否可以通过使用反射?

感谢你的支持!

jas*_*son 17

看起来你应该使用它,Type.IsAssignableFrom但要仔细注意文档:

public virtual bool IsAssignableFrom(Type c)

trueif c和当前[instance of] Type表示相同类型,或者当前[instance of] Type是否在继承层次结构中c,或者当前[instance of] Typec实现的接口,或者if c是泛型类型参数和当前[instance of] Type代表其中一个约束c.false如果这些条件都不是true,或者是否cnull引用(Nothing在Visual Basic中).

特别是:

class Base { }
clase NotABase { public static implicit operator Base(NotABase o) { // } }

Console.WriteLine(typeof(Base).IsAssignableFrom(typeof(NotABase)));
Run Code Online (Sandbox Code Playgroud)

False即使NotABases可以隐式地转换为Bases,它也会在控制台上打印.所以,为了处理铸造,我们可以像这样使用反射:

static class TypeExtensions {
    public static bool IsCastableTo(this Type from, Type to) {
        if (to.IsAssignableFrom(from)) {
            return true;
        }
        return from.GetMethods(BindingFlags.Public | BindingFlags.Static)
                          .Any(
                              m => m.ReturnType == to && 
                                   (m.Name == "op_Implicit" || 
                                    m.Name == "op_Explicit")
                          );
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

Console.WriteLine(typeof(string).IsCastableTo(typeof(int))); // false
Console.WriteLine(typeof(NotABase).IsCastableTo(typeof(Base))); // true
Run Code Online (Sandbox Code Playgroud)

而对于你的情况

// from is string representing type name, e.g. "System.Windows.Forms.Label"
// to is string representing type name, e.g. "System.Windows.Forms.Control"
Type fromType = Type.GetType(from);
Type toType = Type.GetType(to);
bool castable = from.IsCastableTo(to);
Run Code Online (Sandbox Code Playgroud)

  • `typeof(short).IsCastableTo(typeof(int))`返回`false`,即使`short`可以隐式转换为`int`.有没有办法让你的方法适用于那种情况? (4认同)
  • 很好的解决方案。为了完整性,我相信您应该检查m.ReturnType.IsAssignable(to)而不是检查相等性。这意味着您将获得返回更多派生类型的隐式运算符。一种罕见的情况,但值得扔在那里。 (2认同)
  • @Jason,这里有一个小问题,您应该遍历两种类型,因为可以在任何一种类型上定义强制转换运算符。就像古斯多(Gusdor)所说的那样,“ IsAssignableFrom”将处理通过继承进行的强制类型转换。尽管如此,还是一个出色的入门者。我将尝试扩展它。 (2认同)

pky*_*yhd 7

我得到了这次讨论的帮助,谢谢.

我修改了nawfal的代码来解决有关原始类型的问题.

现在它返回正确的结果.

typeof(short).IsCastableTo(typeof(int)); // True
typeof(short).IsCastableTo(typeof(int), implicitly:true); // True
typeof(int).IsCastableTo(typeof(short)); // True
typeof(int).IsCastableTo(typeof(short), implicitly:true); // False
Run Code Online (Sandbox Code Playgroud)

代码如下.

public static bool IsCastableTo(this Type from, Type to, bool implicitly = false)
{
    return to.IsAssignableFrom(from) || from.HasCastDefined(to, implicitly);
}

static bool HasCastDefined(this Type from, Type to, bool implicitly)
{
    if ((from.IsPrimitive || from.IsEnum) && (to.IsPrimitive || to.IsEnum))
    {
        if (!implicitly)
            return from==to || (from!=typeof(Boolean) && to!=typeof(Boolean));

        Type[][] typeHierarchy = {
            new Type[] { typeof(Byte),  typeof(SByte), typeof(Char) },
            new Type[] { typeof(Int16), typeof(UInt16) },
            new Type[] { typeof(Int32), typeof(UInt32) },
            new Type[] { typeof(Int64), typeof(UInt64) },
            new Type[] { typeof(Single) },
            new Type[] { typeof(Double) }
        };
        IEnumerable<Type> lowerTypes = Enumerable.Empty<Type>();
        foreach (Type[] types in typeHierarchy)
        {
            if ( types.Any(t => t == to) )
                return lowerTypes.Any(t => t == from);
            lowerTypes = lowerTypes.Concat(types);
        }

        return false;   // IntPtr, UIntPtr, Enum, Boolean
    }
    return IsCastDefined(to, m => m.GetParameters()[0].ParameterType, _ => from, implicitly, false)
        || IsCastDefined(from, _ => to, m => m.ReturnType, implicitly, true);
}

static bool IsCastDefined(Type type, Func<MethodInfo, Type> baseType,
                        Func<MethodInfo, Type> derivedType, bool implicitly, bool lookInBase)
{
    var bindinFlags = BindingFlags.Public | BindingFlags.Static
                    | (lookInBase ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly);
    return type.GetMethods(bindinFlags).Any(
        m => (m.Name=="op_Implicit" || (!implicitly && m.Name=="op_Explicit"))
            && baseType(m).IsAssignableFrom(derivedType(m)));
}
Run Code Online (Sandbox Code Playgroud)


Jar*_*Par 6

如果你可以将这些字符串转换为Type对象,那么最好的选择是Type.IsAssignableFrom.

但要注意,这只会告诉您两个Type实例是否在CLR级别兼容.这不会考虑用户定义的转换或其他C#语义之类的内容.