19

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.

Bill Heitstuman
  • 979
  • 1
  • 8
  • 23
  • 5
    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"? – Jeroen Vannevel May 21 '14 at 21:12
  • 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. – briba May 21 '14 at 21:14
  • Maybe it would help if you can elaborate on why you need that or what is the purpose of that. – Jester May 21 '14 at 21:15
  • 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... – rsenna May 21 '14 at 21:16
  • @rsenna - There's nothing keeping you from adding to the `System` namespace that I'm aware of... – Bobson May 21 '14 at 21:19
  • @Bobson You mean [nothing besides common sense](http://programmers.stackexchange.com/questions/57294/adding-to-the-system-namespace-in-c), right? ;) But OK, technically you are right, agreed. – rsenna May 21 '14 at 21:22
  • @rsenna - Well, yes. But who says common sense is common? :p – Bobson May 21 '14 at 21:23
  • 2
    Bill - I think you really should tell us *why* you want to do this - there's probably a better way. – Bobson May 21 '14 at 22:16
  • @Bobson 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. – rsenna May 23 '14 at 17:27
  • 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. – Bill Heitstuman May 27 '14 at 22:30
  • 1
    Possible duplicate of [How do I determine if System.Type is a custom type or a Framework type?](https://stackoverflow.com/questions/3174921/how-do-i-determine-if-system-type-is-a-custom-type-or-a-framework-type) – Liam Oct 20 '17 at 10:28

6 Answers6

21

@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
    }
}
Bill Heitstuman
  • 979
  • 1
  • 8
  • 23
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()
Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
  • This is not very flexible solution. See [my answer](http://stackoverflow.com/a/23794004/259172) below. You can use my code sample to determine types that were declared in currently executing assembly or in any assembly that you specify. – virious May 21 '14 at 21:23
  • 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. – Jeroen Vannevel May 21 '14 at 21:25
  • that is true. You can always get lists of types from any external assembly you reference in your project. – virious May 21 '14 at 21:29
  • This will exclude to the core .NET assembly but not all the other infrastructure assemblies for ASP.NET, MVC, Entity Framework, etc. – Bill Heitstuman Aug 18 '15 at 22:59
  • @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. – Jeroen Vannevel Aug 18 '15 at 23:07
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.

Patrick Cairns
  • 143
  • 1
  • 7
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;
    }
NobleGuy
  • 9
  • 1
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");
Slothario
  • 2,830
  • 3
  • 31
  • 47
-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?

virious
  • 571
  • 1
  • 8
  • 27
  • This answer has also issues: a class library, for instance, is a distinct assembly, but it is not the "executing" one... – rsenna May 21 '14 at 21:30
  • @rsenna 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. – virious May 21 '14 at 21:32
  • @rsenna 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. – virious May 21 '14 at 21:48
  • 1
    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). – rsenna May 21 '14 at 21:54
  • 1
    @rsenna 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. – virious May 23 '14 at 04:55
  • 1
    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). – rsenna May 23 '14 at 17:28