Класс не наследуется от object?

я работаю над методом, который использует отражение для проверки типов параметров методов. Эти методы перебирают ParameterInfo и что-то делают с типами этих параметров.

я всегда был в предположении, что если TypeInfo.IsClass is true, что этот тип является классом, и всегда происходит (косвенно) от типа object (за исключением случаев, когда тип object сам конечно). Итак, если TypeInfo.IsClass правда, TypeInfo.BaseType должен быть установлен.

Ну мой предположение было неверным! Есть классы, которые не являются производными от типа object. И мое предположение испортило мой код.

например:

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

type.IsClass будет true и type.BaseType будет null.

если вы думаете об этом, это логично. И я могу предотвратить сбой моего кода, проверив TypeInfo.IsByRef.

теперь мой вопрос: есть ли еще такие "экзотические" типы (кроме как byref-и типа object), которые представляют собой класс (IsClass == true), но не имеют базового типа (BaseType == null)?

прежде чем вы ответите: я только ссылаюсь на типы, где IsClass == true! И мой пример с типом int был просто пример. Это мог быть любой тип. Поэтому, пожалуйста, нет:

  • интерфейсы
  • структуры
  • пустота

ответы до сих пор:

  • типы ByRef (T&): как descrybed в вопрос.
  • типы указателей (T*): нашел Марк Gravell.

3 ответов


Я бы сказал, что IsClass просто вводит в заблуждение здесь. В нем говорится:

получает значение, указывающее, является ли система.Type-это класс, то есть не тип значения или интерфейс.

и реализовала таким образом: он проверяет, включают ли флаги Interface, и является ли это ValueType.

к сожалению, есть многое, что это. Указатели не являются управляемыми типами. A by-ref очень похож на указатель. Указатель не objects, хотя в общем использовании приведение фактически является де-ссылкой / приведением. То же самое относится к таким вещам, как прямые указатели, такие как int*.

Не все в .NET является object :)

var baseType = typeof(int*).BaseType; // null
bool liesAndMoreLies = typeof(int*).IsClass; // true

Эрик Липперт охватывает это больше здесь: не все происходит от object - и перечисляет несколько других примеров (например, открытые универсальные типы).


кроме общих типов, которые не являются экземплярами, указывается с помощью ссылки не все, что исходит от объекта блоге @ г-н Липперт это by хороший ответ Мистера Грейвелла, я предлагаю, чтобы найти другие типы, отвечающие вашим требованиям, можно сделать самостоятельно.

Итак, давайте начнем с нуля, чтобы решить этот вопрос. Во-первых, типы, которые вы собираетесь выяснить, должны быть в основной библиотеке времени выполнения, и это 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, однако, есть несколько недопустимых случаев такого рода вызов, например, invoking GetGenericParameterConstraints() на неуниверсального типа; мы избегаем этих случаях с попробовать-поймать:

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

тип.Метод Метод Getelementtype (из MSDN)

тип объекта включает или ссылается текущий массив, указатель или ссылку на тип, или null, если текущий тип не является массивом или указателем, или не прошел по ссылке, или представляет собой универсальный тип или параметр типа в определении универсального типа или метода.

код...

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

Type elementType = type.GetElementType(); // Int32
Type baseType = elementType.BaseType; // ValueType