How do I determine if a property is a user-defined

2019-03-25 08:53发布

问题:

How do I determine if a property is a user-defined type? I tried to use IsClass as shown below but its value was true for String properties (and who knows what else).

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

* Updated for more clarity *

I am trying to traverse a given type's definition and if the given type or any of its public properties are defined within the assembly, I am searching for an embedded JavaScript document. I just don't want to waste processing resources and time on native .NET types.

回答1:

If by "user-defined" you mean that it is not part of the standard assembly (mscorlib) then you can do something along the lines of this:

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

However this will also consider types from external assemblies (aka: libraries) to be considered "user-defined". If you only want those in your current assembly then you can use

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


回答2:

@Bobson made a really good point:

"...Unlike some other languages, C# does not make any actual distinction between "user-defined" and "standard" types."

Technically, @Bobson gave the answer; there is no distinguishing difference between a user-defined type and one defined in the .NET Framework or any other assembly for that matter.

However, I found a couple useful ways to determine if a type is user-defined.

To search for all types defined within the given type's assembly, this works great:

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

If the types can be defined in various assemblies, excluding the System namespace works in most cases:

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


回答3:

I wrote a generic populator for unit testing that assigns predictable values to my objects and came across this kind of problem. In my case I wanted to know which of my properties were objects so that I could recursively populate those object properties, again with predictable values.

It seemed to me that introducing an interface implemented only by the classes that I was interested in traversing was the best way to do this. You can then test to see if your property is an object of interest:

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


回答4:

If by "user-defined" type you mean type that was declared in your executing assembly then you can obtain list of that types like in this sample c# console application:

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

UPDATE:

If you want to obtain list of types from all referenced assemblies:

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

Just be aware that Program type will also be in that list. Is this sufficient answer to your problem?



回答5:

Say your project is named "Foobar" and everything you make is under that namespace. You can test to see if you've written it by the following method:

typeof(SomeType).Namespace.Contains("Foobar");


标签: c# reflection