How do I determine if a property is a user-defined type in C#?
Asked Answered
C

6

22

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.

Cherlynchernow answered 21/5, 2014 at 21:9 Comment(11)
Obviously, because string is a class. How do you distinguish between a "user-defined" type and another? Is a type from an external non-standard library "user-defined"?Whiz
Do you know the class object? How about something like this? "if (property.PropertyType == typeof(MyClass)) { ... }" or you can use this to ignore string in your case.Antifouling
Maybe it would help if you can elaborate on why you need that or what is the purpose of that.Nahshunn
Also, one can easily code "user-defined value types" in C# too... That means IsClass is not relevant. Guess one valid option instead would be checking the type namespace: for instance, if it belongs to "System.*" it is definitely NOT user-defined, and so on...Underglaze
@Underglaze - There's nothing keeping you from adding to the System namespace that I'm aware of...Skunk
@Skunk You mean nothing besides common sense, right? ;) But OK, technically you are right, agreed.Underglaze
@Underglaze - Well, yes. But who says common sense is common? :pSkunk
Bill - I think you really should tell us why you want to do this - there's probably a better way.Skunk
@Skunk exactly, this use case seems to be completely bogus. That's why the answers here do not seem to be completely satisfactory. Unlike some other languages, C# does not make any actual distinction between "user-defined" and "standard" types.Underglaze
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 waiste processing resources and time on native .NET types.Cherlynchernow
Possible duplicate of How do I determine if System.Type is a custom type or a Framework type?Photoelasticity
C
22

@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
    }
}
Cherlynchernow answered 27/5, 2014 at 23:50 Comment(2)
I would also add "Microsoft." namespace to exclude listMercaptide
Also works when you use property.PropertyType.Assembly == type.Assembly. The FullName property is needed.Joslyn
W
10

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()
Whiz answered 21/5, 2014 at 21:16 Comment(5)
This is not very flexible solution. See my answer below. You can use my code sample to determine types that were declared in currently executing assembly or in any assembly that you specify.Sorrel
I was adding a similar distinction as well. There are many edge cases with that though: some assemblies are user defined but are not the same as the executing one so they will be incorrectly left out. Depending on how strict it has to be, it might be best to blacklist too few instead of too many.Whiz
that is true. You can always get lists of types from any external assembly you reference in your project.Sorrel
This will exclude to the core .NET assembly but not all the other infrastructure assemblies for ASP.NET, MVC, Entity Framework, etc.Cherlynchernow
@BillHeitstuman: I believe you'll either have to check if it's in the executing assembly or provide a blacklist/whitelist of assemblies and check if it's in the appropriate list.Whiz
M
1

I struggled with this as well when creating a log when updating the database. I did not want the classes to be shown in the log as they never == between data and dto.

foreach (PropertyType item in properties)
{
    if((item.PropertyType.IsClass && item.PropertyType.FullName.StartsWith("System.")) || !item.PropertyType.IsClass)
    {
       //...do stuff
    }
}

This allowed me to deal with strings and the likes which are flagged as classes.

Messene answered 5/4, 2022 at 15:49 Comment(0)
G
0

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;
    }
Gambit answered 4/6, 2015 at 8:0 Comment(0)
S
0

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");
Sightread answered 22/6, 2018 at 16:21 Comment(0)
S
-1

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?

Sorrel answered 21/5, 2014 at 21:20 Comment(6)
This answer has also issues: a class library, for instance, is a distinct assembly, but it is not the "executing" one...Underglaze
@Underglaze you can also get list of types from any assembly you want. var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); or var referencedAssemblies = someAssembly.GetReferencedAssemblies(); and then call GetTypes() method on them.Sorrel
@Underglaze see my updated answer with getting types from referenced assemblies. Using the same method you can get types from couple of specified assemblies as well.Sorrel
Sorry, I believe the last edit made everything worse - now you are getting all referenced types, "user-defined" or not. I guess your first answer was good enough for some simple cases, at least. I also believe there is no easy way of making your code better. Apart from, I don't know, parsing the solution file and finding out all "user-defined projects" (and even that would not work for all cases).Underglaze
@Underglaze I've added example on how to get types from referenced assemblies because you suggested that "a class library, for instance, is a distinct assembly, but is not the "executing" one. Besides my answer, the question is: why someone need to check if SomeType is user-defined or not. Maybe he should refactor his code so he doesn't need to check that.Sorrel
Sorry, but I didn't "suggest" anything - I just stated that there was a limitation in your solution. Many valid answers have limits, and there is nothing wrong about that, in itself. But I believe your answer became worst after your update (getting the list of referenced assemblies will get all assemblies, "user-defined" or not).Underglaze

© 2022 - 2024 — McMap. All rights reserved.