Как определить, является ли свойство определяемым пользователем типом в С#?

Как определить, является ли свойство определяемым пользователем типом? Я попытался использовать IsClass, как показано ниже, но его значение было истинным для свойств String (и кто знает, что еще).

foreach (var property in type.GetProperties()) {
    if (property.PropertyType.IsClass) {
        // do something with property
    }
}

* Обновлено для большей ясности *

Я пытаюсь пройти определение определенного типа, и если данный тип или любые его общедоступные свойства определены в сборке, я ищу встроенный документ JavaScript. Я просто не хочу тратить ресурсы обработки и время на собственные типы .NET.

Ответ 1

@Bobson сделал действительно хороший момент:

"... В отличие от некоторых других языков, С# не делает никаких реальных различие между" определяемыми пользователем "и" стандартными "типами."

Технически, @Bobson дал ответ; нет различительной разницы между определяемым пользователем типом и значением, определенным в .NET Framework или любой другой сборке, если на то пошло.

Однако, я нашел пару полезных способов определить, является ли тип определяемым пользователем.

Для поиска всех типов, определенных в сборке данного типа, это отлично работает:

foreach (var property in type.GetProperties()) {
    if (property.PropertyType.IsClass 
    && property.PropertyType.Assembly.FullName == type.Assembly.FullName) {
        // do something with property
    }
}

Если типы могут быть определены в разных сборках, в большинстве случаев исключается пространство имен Система:

foreach (var property in type.GetProperties()) {
    if (property.PropertyType.IsClass 
    && !property.PropertyType.FullName.StartsWith("System.")) {
        // do something with property
    }
}

Ответ 2

Если под "определяемым пользователем" вы подразумеваете, что он не является частью стандартной сборки (mscorlib), тогда вы можете сделать что-то в этом направлении:

if(typeof(SomeType).Assembly.GetName().Name != "mscorlib") {
    // user-defined!
}

Однако это также рассмотрит типы внешних сборок (aka: libraries), которые будут считаться "определяемыми пользователем". Если вы хотите только те, что есть в текущей сборке, вы можете использовать

typeof(SomeType).Assembly == Assembly.GetExecutingAssembly()

Ответ 3

Я написал общий наполнитель для модульного тестирования, который назначает предсказуемые значения моим объектам и сталкивается с такой проблемой. В моем случае я хотел знать, какие из моих свойств были объектами, чтобы я мог рекурсивно заполнять эти свойства объекта, опять же с предсказуемыми значениями.

Мне показалось, что введение интерфейса, реализованного только классами, которые мне интересны в обходе, было лучшим способом сделать это. Затем вы можете проверить, является ли ваше свойство объектом интереса:

    public static bool IsMyInterface(this Type propertyType)
    {
        return propertyType.GetInterface("MyInterfaceName") != null;
    }

Ответ 4

Если по типу "определяемый пользователем" вы подразумеваете тип, объявленный в вашей исполняющей сборке, вы можете получить список таких типов, как в этом примере приложения консоли С#:

class Program
{
    static void Main( string[] args )
    {
        var currentAssembly = Assembly.GetExecutingAssembly();
        var localTypes = currentAssembly.GetTypes();
    }
}

UPDATE:

Если вы хотите получить список типов из всех ссылочных ассемблеров:

class Program
{
    static void Main( string[] args )
    {
        var currentAssembly = Assembly.GetExecutingAssembly();
        var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
        var typesFromReferencedAssemblies = referencedAssemblies.Select( assemblyName => Assembly.ReflectionOnlyLoad( assemblyName.FullName ) ).SelectMany( assembly => assembly.GetTypes() );
    }
}

Просто помните, что тип Program также будет в этом списке. Является ли это достаточным ответом на вашу проблему?