【问题标题】:Class not inheriting from object?类不继承自对象?
【发布时间】:2013-05-09 12:13:03
【问题描述】:

我正在研究一种使用反射来检查方法参数类型的方法。此方法遍历 ParameterInfo 并使用这些参数的类型进行操作。

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

好吧,我的假设是错误的!有些类不是从类型object 派生的。我的假设搞砸了我的代码。

例如:

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

type.IsClass 将是 truetype.BaseType 将是 null

如果你仔细想想,这是合乎逻辑的。我可以通过检查TypeInfo.IsByRef 来防止我的代码崩溃。

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

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

  • 接口
  • 结构体
  • 无效

到目前为止的答案:

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

【问题讨论】:

  • 所有引用-value types 肯定。也是“voidreference”类型。
  • @Jon:所有值类型都间接派生自object。值类型派生自ValueTypeValueType 派生自object
  • @MartinMulder:关于编辑——我希望你意识到int 也是一个结构体,唯一使IsClass trueMakeByRefType()
  • 反对者,请评论原因。
  • @MartinMulder 您所说的“关于接口”引用 MSDN 的话说“对象是唯一没有基本类型的类型,因此 null 作为 Object 的基本类型返回。” ,正如我在评论中指出的那样,这是对您问题的准确回答。你还想要什么?

标签: c# .net inheritance reflection typeinfo


【解决方案1】:

我想说IsClass 在这里只是误导。它指出:

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

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

不幸的是,还有更多的事情。指针不是托管类型。 by-ref 与指针非常相似。指针不是objects,尽管通常使用强制转换实际上是取消引用/强制转换。这同样适用于诸如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 - 并列出了一些其他示例(例如,开放的泛型类型)。

【讨论】:

  • @MartinMulder 有一段时间我认为它报告了IsClassfalse,但实际上它报告了true - 事实上,它与问题
【解决方案2】:

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

现在,让我们从头开始解决这个问题。首先,您要弄清楚的类型应该在核心运行时库中,即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)但没有基本类型(@987654334 @)?

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

【讨论】:

    【解决方案3】:

    Type.GetElementType 方法(from MSDN)

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

    代码...

    Type type = typeof(int).MakeByRefType();
    bool isClass = type.IsClass; // true
    
    Type elementType = type.GetElementType(); // Int32
    Type baseType = elementType.BaseType; // ValueType
    

    【讨论】:

    • 你说有些类不是从 Object 派生的。在我看来,您正在对整数进行装箱并以错误的方式调查基本类型。有一个基本类型。
    • 您的外来类型不存在。 Object 是唯一没有基类型的类型。你为什么不回复我的最后一条评论,然后解释你的反对意见。
    • 定义异国情调?您说它们是“异国情调”,因为 IsClass == true 而基本类型为空。错误的!基本类型不为空。当您对整数进行装箱时,基本类型的评估方式不同,正如我在上面发布的那样。
    • 你测试了吗?你说TypeInfo.BaseType 不为空......只是测试它。创建一个程序,将IsClassBaseType 写入控制台,看看它们是否是true + null
    • 我敢打赌,构建 .net 框架的人对此有一些见解。如果我调用 GetElementType() 然后检查基本类型,它将不为空。你认为 GetElementType() 是干什么用的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多