10

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

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

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

例如:

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

type.IsClass将是true并且type.BaseType将是null

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

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

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

  • 接口
  • 结构
  • 空白

到目前为止的答案:

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

3 回答 3

14

我想说这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 在这里更详细地介绍了这一点:并非一切都源自对象- 并列出了一些其他示例(例如,开放泛型类型)。

于 2013-05-09T12:40:44.927 回答
2

除未实例化的泛型类型外,通过链接Not Everything 派生自对象@Lippert 先生的博客Gravell 先生的好答案指出,我建议找到满足您要求的其他类型可以自己完成。

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

            where null==type.BaseType
            where type.IsClass

您还表示before answer

在你回答之前:我只指类型 where 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();
    }
}
于 2013-05-11T02:31:04.693 回答
-1

Type.GetElementType 方法(来自 MSDN)

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

代码...

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

Type elementType = type.GetElementType(); // Int32
Type baseType = elementType.BaseType; // ValueType
于 2013-05-09T13:24:50.413 回答