views:

229

answers:

3

I am writing a tool where I need to reflect upon methods and if the parameters of the methods are complex type, then I need to certain type of actions such as instantiating them etc.

Now I saw the IsPrimitive property in the Type variable. However, it shows string and decimal as complex types, which technically isn't incorrect. However what I really want is to be able to distinguish developer created class types from system defined data types.

Is there any way that I can do this?

A: 

Not quite sure how using built-in types is any different from user created types. Your bigger problem would creating instances of types that don't have parameterless constructors.

Whatever you do, you will have to cast those into object arrays so you can pass them to MethodInfo.Invoke, so at some point you will need to do Activator.CreateInstance.

If you provide a UI where a user can enter stuff in fields and then press a button to call a method, you best strategy would be to use Reflection to look for the TryParse/Parse static methods on the type and call those in order to validate/parse the input.

Here is a snippet that will work implicitly for most system types that can be converted from string:

var parseMethod = typeof(int).GetMethods().FirstOrDefault(
    m => m.IsStatic && 
        m.Name == "TryParse" && 
        m.GetParameters().Length == 2 && 
        m.GetParameters()[0].ParameterType == typeof(string) && 
        m.GetParameters()[1].IsOut);
if(parseMethod != null) {
    bool result = (bool)parseMethod.Invoke(null, new object[]{"45", null});
    //result == true
    result = (bool)parseMethod.Invoke(null, new object[] { "blah", null });
    //result = false
}
Igor Zevaka
Actually creating instances of types without a parameterless constructor (not even a private one) isn't such a biggie, *but* you need to be very careful; not recommended for most code - only really suitable for things like serialization APIs.
Marc Gravell
Oh cool, I didn't know you could do that.
Igor Zevaka
+1  A: 

decimal certainly is a "complex type"; C# may have a keyword for it, but it is not a CLI primitive. String you could argue either way - it is actually a type all to itself (indeterminate size, etc - the only things remotely comparable are arrays).

However; there is simply no way to determine what you are wanting here. The best you can do is to check for known system assembles (or maybe signing keys). After all, I can write an assembly called System.something.dll or Microsoft.something.dll, with types in the System.Foo.Bar namespace (this also depends on how paranoid you want to be, of course).

It may be easier to get devs to explicitly mark their own types that you want to treat in a speicial way - either via an attribute or an interface.

Marc Gravell
In C#, strings are clearly complex types. They are defined as a class instead of stuct which alone marks the difference, but the behavior of string is not conceptually primitive either. Their usage in C# does resemble that of a primitive type, but that is mostly done through some clever operator overloading and a few special language features (like the C# handling of string literals).
Stephen M. Redd
@Stephen - I disagree; struct vs class is *not* the important thing here. I can write a custom struct just as much as a type, etc. And the "special" in string goes far beyond language things like operators.
Marc Gravell
I think it might just be semantic depending on your definition of "complex", and C# doesn't officially use the term "complex type". It has terms like "custom" and "value type", and stings are neither. I consider them conceptually complex because the data of strings are stored as an array of items that are not strings... thus the use of data in a string is dependent on behavior that is more complex than a simple fetch of the underlying value types from memory. But your definition of complex may be different.
Stephen M. Redd
A: 

I 'm not sure if there is a more elegant method, but I imagine that if you check the type's Namespace or AssemblyQualifiedName against namespace System and/or the system assemblies it will work out fine.

Jon