我正在研究一种使用反射来检查参数类型的方法的方法。这个方法遍历ParameterInfo,并且正在对这些参数的类型做些什么。
我总是假设如果TypeInfo.IsClass
是true
,那么这个类型是一个类,并且总是从类型object
派生(间接)(除非类型为{{} 1}}本身当然)。因此,如果object
为真,则必须设置TypeInfo.IsClass
。
我的假设错了!有些类不是从类型TypeInfo.BaseType
派生的。我的假设搞砸了我的代码。
例如:
object
Type type = typeof(int).MakeByRefType();
将为type.IsClass
,true
将为type.BaseType
。
如果你考虑一下,这是合乎逻辑的。我可以通过检查null
来阻止我的代码崩溃。
现在我的问题是:是否有更多这样的“异国情调”类型(除了ByRef类型和类型TypeInfo.IsByRef
),它们是一个类(object
)但没有基础输入(IsClass == true
)?
回答之前:我只是提到BaseType == null
的类型!我的IsClass == true
类型示例就是一个例子。它可以是任何类型。
所以请不要:
答案:
int
):正如问题中所述。T&
):由Mark Gravell发现。答案 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