简体   繁体   English

类不是从对象继承的?

[英]Class not inheriting from object?

I am working on a method that is using reflection to inspect parameter types of methods. 我正在研究一种方法,该方法使用反射来检查参数类型的方法。 This methods iterates through the ParameterInfo's and is doing something with the types of those parameters. 这个方法遍历ParameterInfo,并且正在对这些参数的类型做些什么。

I was always under the assumption that if TypeInfo.IsClass is true , that this type is a class and always derives (indirectly) from type object (except when the type is object itself of course). 我总是假设如果TypeInfo.IsClasstrue ,那么这个类型是一个类,并且总是从类型object派生(间接)(当然,当类型是object本身时)。 So, if TypeInfo.IsClass is true, TypeInfo.BaseType must be set. 因此,如果TypeInfo.IsClass为true,则必须设置TypeInfo.BaseType

Well my assumption was wrong! 我的假设是错的! There are classes that do NOT derive from type object . 有些类不是从类型object派生的。 And my assumption messed up my code. 我的假设搞砸了我的代码。

For example: 例如:

Type type = typeof(int).MakeByRefType();

type.IsClass will be true and type.BaseType will be null . type.IsClasstruetype.BaseTypenull

If you think about it, it is logical. 如果你考虑一下,这是合乎逻辑的。 And I can prevent my code to crash by checking TypeInfo.IsByRef . 我可以通过检查TypeInfo.IsByRef来防止我的代码崩溃。

Now my question is: are there more such 'exotic' types (besided the ByRef-types and type object ) which are a class ( IsClass == true ) but do not have a base type ( BaseType == null )? 现在我的问题是:是否有更多这样的“异国情调”类型(除了ByRef类型和类型object ),它们是一个类( IsClass == true )但没有基类型( BaseType == null )?

Before you answer: I am only refering to types where IsClass == true ! 在回答之前:我只是IsClass == true类型! And my example with type int was just an example. 我的int类型示例只是一个例子。 It could have been any type. 它可以是任何类型。 So please no: 所以请不要:

  • Interfaces 接口
  • Structs 结构
  • Void 空虚

Answers so far: 答案到目前为止:

  • ByRef types ( T& ): as descrybed in the question. ByRef类型( T& ):如问题中所述。
  • Pointer types ( T* ): Found by Mark Gravell. 指针类型( T* ):由Mark Gravell发现。

I would say that IsClass is simply misleading here. 我会说IsClass在这里只是误导。 It states: 它指出:

Gets a value indicating whether the System.Type is a class; 获取一个值,该值指示System.Type是否为类; that is, not a value type or interface. 也就是说,不是值类型或接口。

and it is implemented this way: it checks whether the flags include Interface , and whether it is a ValueType . 它以这种方式实现 :它检查标志是否包含Interface ,以及它是否是ValueType

Unfortunately, there are more things that this. 不幸的是,还有更多的事情。 Pointers are not managed types . 指针不是托管类型 A by-ref is very similar to a pointer. by-ref与指针非常相似。 Pointer are not object s, although in common use the cast is actually a de-reference/cast. 指针不是object ,虽然通常使用强制转换实际上是取消引用/强制转换。 The same applies for things like direct pointers such as int* . 这同样适用于诸如int*类的直接指针之类的东西。

Not everything in .NET is an object :) 并非.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 - and lists a few other examples (open generic types, for example). Eric Lippert在这里更多地介绍了这一点:并非所有内容都来自于对象 - 并列出了一些其他示例(例如,开放泛型类型)。

Except generic types which are not instantiated, is pointed out with the link Not everything derives from object @ Mr. Lippert's blog by Mr. Gravell's good answer , I suggest that to find the other types met your requirement can be done by yourself. 除了没有实例化的泛型类型,用链接指出并非一切都来自于对象@Lippert先生的博客 Gravell先生的好答案 ,我建议找到满足您要求的其他类型可以由您自己完成。

Now, let's start from scratch to solve this question. 现在,让我们从头开始解决这个问题。 First off, the types your are going to figure out, should be in the core runtime library, and which is mscorlib.dll : 首先,您要弄清楚的类型应该在核心运行时库中,哪个是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;
    }
}

And then, the types have the MakeXXXXType() methods such as MakeByRefType() . 然后,类型具有MakeXXXXType()方法,例如MakeByRefType() Here we take more possibility into account, that is any method which returns a type or types . 在这里,我们考虑更多的可能性,即任何返回一种或多种类型的方法 Since we have zero knowledge about the arguments for an arbitrary type , we consider methods take zero argument : 由于我们对任意类型的参数没有任何了解,因此我们认为方法采用零参数

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 });
    }
}

For the implementation of InvokeZeroArgumentMethodWhichReturnsTypeOrTypes , however, there are several invalid cases of this kind of invocation, such as invoking GetGenericParameterConstraints() on a non-generic type; 但是,对于InvokeZeroArgumentMethodWhichReturnsTypeOrTypes的实现,有几种这种调用的无效情况,例如在非泛型类型上调用GetGenericParameterConstraints() ; we are avoiding these cases with try-catch : 我们通过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;
    }
}

And now, to figure out the desired types. 现在,找出所需的类型。 Let's construct the method step by step. 让我们一步一步地构建方法。 The first step would be define the scope of all possible types: 第一步是定义所有可能类型的范围:

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

Then, according to what you stated basically: 然后,根据你所说的基本:

Now my question is: are there more such 'exotic' types (besided the ByRef-types and type object ) which are a class ( IsClass == true ) but do not have a base type ( BaseType == null )? 现在我的问题是:是否有更多这样的“异国情调”类型(除了ByRef类型和类型object ),它们是一个类( IsClass == true )但没有基类型( BaseType == null )?

            where null==type.BaseType
            where type.IsClass

You also stated that for before answer : 您还说before answer

Before you answer: I am only refering to types where IsClass == true ! 在回答之前:我只是IsClass == true类型! And my example with type int was just an example. 我的int类型示例只是一个例子。 It could have been any type. 它可以是任何类型。 So please no: 所以请不要:

  • Interfaces 接口
  • Structs 结构
  • Void 空虚
            where !type.IsInterface
            where !type.IsValueType
            where typeof(void)!=type

The final step, let's skip which are already answered and complete the method: 最后一步,让我们跳过已经回答并完成方法:

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

So now, you can invoke MartinMulderExtensions.GetDesiredTypes() to get the types you desired: 现在,您可以调用MartinMulderExtensions.GetDesiredTypes()来获取所需的类型:

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

For the complete code: 完整代码:

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();
    }
}

Type.GetElementType Method (from MSDN) Type.GetElementType方法(来自MSDN)

The Type of the object encompassed or referred to by the current array, pointer, or reference type, or null if the current Type is not an array or a pointer, or is not passed by reference, or represents a generic type or a type parameter in the definition of a generic type or generic method. 当前数组,指针或引用类型包含或引用的对象类型,如果当前Type不是数组或指针,或者不通过引用传递,或者表示泛型类型或类型参数,则返回null在泛型类型或通用方法的定义中。

Code... 码...

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM