类不是从对象继承的?

时间:2013-05-09 12:13:03

标签: c# .net inheritance reflection typeinfo

我正在研究一种使用反射来检查参数类型的方法的方法。这个方法遍历ParameterInfo,并且正在对这些参数的类型做些什么。

我总是假设如果TypeInfo.IsClasstrue,那么这个类型是一个类,并且总是从类型object派生(间接)(除非类型为{{} 1}}本身当然)。因此,如果object为真,则必须设置TypeInfo.IsClass

我的假设错了!有些类不是从类型TypeInfo.BaseType派生的。我的假设搞砸了我的代码。

例如:

object

Type type = typeof(int).MakeByRefType(); 将为type.IsClasstrue将为type.BaseType

如果你考虑一下,这是合乎逻辑的。我可以通过检查null来阻止我的代码崩溃。

现在我的问题是:是否有更多这样的“异国情调”类型(除了ByRef类型和类型TypeInfo.IsByRef),它们是一个类(object)但没有基础输入(IsClass == true)?

回答之前:我只是提到BaseType == null的类型!我的IsClass == true类型示例就是一个例子。它可以是任何类型。 所以请不要:

  • 接口
  • 结构
  • 无效
到目前为止

答案:

  • ByRef类型(int):正如问题中所述。
  • 指针类型(T&):由Mark Gravell发现。

3 个答案:

答案 0 :(得分:14)

我会说IsClass在这里只是误导。它声明:

  

获取一个值,该值指示System.Type是否为类;也就是说,不是值类型或接口。

以这种方式实现:它会检查标记是否包含Interface,以及它是否为ValueType

不幸的是,这还有更多的事情。指针不是托管类型。 by-ref与指针非常相似。指针不是object,虽然通常使用强制转换实际上是取消引用/强制转换。这同样适用于直接指针,例如int*

并非.NET中的所有内容都是object:)

var baseType = typeof(int*).BaseType; // null
bool liesAndMoreLies = typeof(int*).IsClass; // true

Eric Lippert covers this more here: Not everything derives from object - 并列出了一些其他示例(例如,开放泛型类型)。

答案 1 :(得分:2)

除了未实例化的泛型类型,使用Not everything derives from object @ Mr. Lippert's blog链接Mr. Gravell's good answer指出,我建议您找到符合您要求的其他类型,您可以自己完成。

现在,让我们从头开始解决这个问题。首先,您要弄清楚的类型应该在核心运行时库中,哪个是mscorlib.dll

public static partial class MartinMulderExtensions {
    public static IEnumerable<Type> GetMscorlibTypes() {
        return
            from assembly in AppDomain.CurrentDomain.GetAssemblies()
            let name=assembly.ManifestModule.Name
            where 0==String.Compare("mscorlib.dll", name, true)
            from type in assembly.GetTypes()
            select type;
    }
}

然后,类型包含MakeXXXXType()方法,例如MakeByRefType()。在这里,我们考虑更多的可能性,即任何方法,它返回一种或多种类型。由于我们对任意类型的参数一无所知,我们认为方法采用零参数

partial class MartinMulderExtensions {
    public static IEnumerable<Type> GetRetrievableTypes(this Type type) {
        var typesArray=(
            from method in type.GetMethods()
            where 0==method.GetParameters().Count()

            let typeArray=
                method.InvokeZeroArgumentMethodWhichReturnsTypeOrTypes(type)

            where null!=typeArray
            select typeArray).ToArray();

        var types=
            typesArray.Length>0
                ?typesArray.Aggregate(Enumerable.Union)
                :Type.EmptyTypes;

        return types.Union(new[] { type });
    }
}

但是,对于InvokeZeroArgumentMethodWhichReturnsTypeOrTypes的实现,有几种这种调用的无效情况,例如在非泛型类型上调用GetGenericParameterConstraints();我们通过 try-catch 来避免这些情况:

partial class MartinMulderExtensions {
    public static IEnumerable<Type>
        InvokeZeroArgumentMethodWhichReturnsTypeOrTypes(
        this MethodInfo method, Type t
        ) {
        try {
            if(typeof(Type)==method.ReturnType) {
                var type=method.Invoke(t, null) as Type;

                if(null!=type)
                    return new[] { type };
            }

            if(typeof(Type[])==method.ReturnType) {
                var types=method.Invoke(t, null) as Type[];

                if(types.Length>0)
                    return types;
            }
        }
        catch(InvalidOperationException) {
        }
        catch(TargetInvocationException) {
        }
        catch(TargetException) {
        }

        return Type.EmptyTypes;
    }
}

现在,找出所需的类型。让我们一步一步地构建方法。第一步是定义所有可能类型的范围:

partial class MartinMulderExtensions {
    public static Type[] GetDesiredTypes() {
        return (
            from type in MartinMulderExtensions.GetMscorlibTypes()
            .Select(x => x.GetRetrievableTypes())
            .Aggregate(Enumerable.Union)

然后,根据你所说的基本上:

  

现在我的问题是:是否有更多这样的“异国情调”类型(除了ByRef类型和类型object),它们是一个类(IsClass == true)但没有基础输入(BaseType == null)?

            where null==type.BaseType
            where type.IsClass

你还说过before answer

  

回答之前:我只是提到IsClass == true的类型!我的int类型示例就是一个例子。它可以是任何类型。   所以请不要:

     
      
  • 接口
  •   
  • 结构
  •   
  • 无效
  •   
            where !type.IsInterface
            where !type.IsValueType
            where typeof(void)!=type

最后一步,让我们跳过已经回答的问题并完成方法:

            where !type.IsByRef
            where !type.IsPointer
            select type
            ).ToArray();
    }
}

现在,您可以调用MartinMulderExtensions.GetDesiredTypes()来获取所需的类型:

public partial class TestClass {
    public static void TestMethod() {
        foreach(var type in MartinMulderExtensions.GetDesiredTypes())
            Console.WriteLine(type);
    }
}

完整代码:

public static partial class MartinMulderExtensions {
    public static IEnumerable<Type> GetMscorlibTypes() {
        return
            from assembly in AppDomain.CurrentDomain.GetAssemblies()
            let name=assembly.ManifestModule.Name
            where 0==String.Compare("mscorlib.dll", name, true)
            from type in assembly.GetTypes()
            select type;
    }

    public static IEnumerable<Type>
        InvokeZeroArgumentMethodWhichReturnsTypeOrTypes(
        this MethodInfo method, Type t
        ) {
        try {
            if(typeof(Type)==method.ReturnType) {
                var type=method.Invoke(t, null) as Type;

                if(null!=type)
                    return new[] { type };
            }

            if(typeof(Type[])==method.ReturnType) {
                var types=method.Invoke(t, null) as Type[];

                if(types.Length>0)
                    return types;
            }
        }
        catch(InvalidOperationException) {
        }
        catch(TargetInvocationException) {
        }
        catch(TargetException) {
        }

        return Type.EmptyTypes;
    }

    public static IEnumerable<Type> GetRetrievableTypes(this Type type) {
        var typesArray=(
            from method in type.GetMethods()
            where 0==method.GetParameters().Count()

            let typeArray=
                method.InvokeZeroArgumentMethodWhichReturnsTypeOrTypes(type)

            where null!=typeArray
            select typeArray).ToArray();

        var types=
            typesArray.Length>0
                ?typesArray.Aggregate(Enumerable.Union)
                :Type.EmptyTypes;

        return types.Union(new[] { type });
    }

    public static Type[] GetDesiredTypes() {
        return (
            from type in MartinMulderExtensions.GetMscorlibTypes()
            .Select(x => x.GetRetrievableTypes())
            .Aggregate(Enumerable.Union)

            where null==type.BaseType
            where type.IsClass
            where !type.IsInterface
            where !type.IsValueType
            where typeof(void)!=type

            where !type.IsByRef
            where !type.IsPointer

            select type
            ).ToArray();
    }
}

答案 2 :(得分:-1)

Type.GetElementType方法(from MSDN)

当前数组,指针或引用类型包含或引用的对象的类型,如果当前Type不是数组或指针,或者不通过引用传递,或者表示泛型类型或泛型类型或泛型方法定义中的类型参数。

...代码

Type type = typeof(int).MakeByRefType();
bool isClass = type.IsClass; // true

Type elementType = type.GetElementType(); // Int32
Type baseType = elementType.BaseType; // ValueType