Класс не наследуется от объекта?
Я работаю над методом, использующим отражение для проверки типов параметров методов. Эти методы повторяются через ParameterInfo и делают что-то с типами этих параметров.
Я всегда был в предположении, что если TypeInfo.IsClass
true
, этот тип является классом и всегда выводится (косвенно) из типа object
(за исключением случаев, когда тип object
сам, разумеется). Итак, если TypeInfo.IsClass
истинно, TypeInfo.BaseType
должен быть установлен.
Ну, мое предположение было неправильным! Существуют классы, которые НЕ относятся к типу object
. И мое предположение испортило мой код.
Например:
Type type = typeof(int).MakeByRefType();
type.IsClass
будет true
, а type.BaseType
будет null
.
Если вы думаете об этом, это логично. И я могу предотвратить сбой моего кода, проверив TypeInfo.IsByRef
.
Теперь мой вопрос: существуют ли еще такие "экзотические" типы (помимо типов ByRef и type object
), которые являются классом (IsClass == true
), но не имеют базового типа (BaseType == null
)
Прежде чем ответить: я говорю только о типах, где IsClass == true
! И мой пример с типом int
был всего лишь примером. Это мог быть любой тип.
Поэтому, пожалуйста, нет:
- Интерфейсы
- Структуры
- Пустота
Ответы:
- Типы ByRef (
T&
): как указано в вопросе.
- Типы указателей (
T*
): Найден Марк Гравелл.
Ответы
Ответ 1
Я бы сказал, что IsClass
просто вводит в заблуждение. В нем указано:
Получает значение, указывающее, является ли System.Type классом; то есть не тип значения или интерфейс.
и он реализован таким образом: он проверяет, включают ли флаги Interface
и является ли это ValueType
.
К сожалению, это больше. Указатели не управляются. По-ссылке очень похож на указатель. Указатель не object
s, хотя в общем случае актерский состав фактически является де-ссылкой/литой. То же самое касается таких вещей, как прямые указатели, такие как int*
.
Не все в .NET - это object
:)
var baseType = typeof(int*).BaseType; // null
bool liesAndMoreLies = typeof(int*).IsClass; // true
Эрик Липперт охватывает это здесь: не все происходит от объекта - и перечисляет несколько других примеров (например, открытые общие типы).
Ответ 2
За исключением родовых типов, которые не создаются, указывается со ссылкой Не все происходит от объекта @г-на Lippert blog от Mr. Хороший ответ 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
:
Прежде чем ответить: я говорю только о типах, где 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
Тип .GetElementType Метод (из MSDN)
Тип объекта, охватываемого или передаваемого текущим массивом, указателем или ссылочным типом, или null, если текущий тип не является массивом или указателем, или не передается по ссылке, или представляет общий тип или параметр типа в определении общего типа или общего метода.
код...
Type type = typeof(int).MakeByRefType();
bool isClass = type.IsClass; // true
Type elementType = type.GetElementType(); // Int32
Type baseType = elementType.BaseType; // ValueType