Класс не наследуется от объекта?

Я работаю над методом, использующим отражение для проверки типов параметров методов. Эти методы повторяются через 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