views:

63

answers:

5

Is it possible to check at runtime whether given type is Custom data type or one of primitive data types of .NET?

I have defined user defined types in assembly and those all types are some structs. I need to call the methods of user defined types of whome parameters are those structs. So this needs to fill the data accordingly before calling those function at runtime using reflection.

Now Is there any method available in reflection by which we can track that given data type is custom or primitive data type. I know about IsClass attribute, but my targeted user defined data types are not classes , these public are STRUCTS.

A: 

Type.IsPrimitive

Lee
It's worth mentioning (as per my answer) that `IsPrimitive` returns false for string, which is a bit mis-leading depending on "your" definition of primitive =)
Rob
To my surprise, the CLI standard (Ecma-335) uses the term “primitive type” without defining it. The C# language specification (Ecma-334), however, calls them “simple types” and defines the term to include all the numeric value types including `decimal`, `bool` and `char`, but none of the reference types (so no `string` and no `object`).
Timwi
A: 

A very simple, rudimentary way of determing whether a type is provided by the BCL/CLR is:

var type = typeof(int);
var isSystemType = type.Assembly.FullName.StartsWith("mscorlib");

Bear in mind that using Type.IsPrimitive will return false for System.String, so it depends on what definition of "primitive" you're using as to whether it's suitable or not.

Rob
@Rob: The idea is fine, but wouldn't it be much better to do `typeof(int).Assembly.Equals(candidateType);` or something? What if somebody creates 'mscorlibextensions'?
Ani
@Ani - I did say it was very simple and rudimentary! =)
Rob
@Rob: Except for when I define my own assembly, "mscorlibex.dll," and this returns true for all of the types in there as well. I guess that's kind of a ridiculous point, though, since the only reason I might do that would be to be sneaky.
Dan Tao
@DanTao, there's always someone willing to be bloody awkward! ;-) I'l freely admit that (as I said, I hasten to add!), my sample code was "very simple, rudimentary". It can be tightened up in many ways to ensure that it's only the "proper" *mscorlib* that's checked, but for a clear and concise example that gets the *gist* of it across to the OP, I think what I gave stands fairly well =)
Rob
+1  A: 

I'd go with something like:

static bool IsFundamental(this Type type)
{
    return type.IsPrimitive || type.Equals(typeof(string)) || type.Equals(typeof(DateTime));
}

The choice of string and DateTime as additions to the types for which IsPrimitive returns true, though, is a subjective matter since there is no absolute list... the ultimate choice is yours (you might want to include decimal as well, for example); and it should definitely be documented (at least in a comment, preferably an XML one).

Dan Tao
+1  A: 

Based on information in this question, you can accomplish this using the following code:

public static class TypeExtensions
{
    private static List<byte[]> tokens = new List<byte[]>() 
    {
        new byte[] {0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89},
        new byte[] {0x31, 0xbf, 0x38, 0x56, 0xad, 0x36, 0x4e, 0x35},
        new byte[] {0xb0, 0x3f, 0x5f, 0x7f, 0x11, 0xd5, 0x0a, 0x3a}
    };

    public static bool IsFrameworkType(this Type type)
    {
        if (type == null) { throw new ArgumentNullException("type"); }

        byte[] publicKeyToken = type.Assembly.GetName().GetPublicKeyToken();    

        return publicKeyToken != null && publicKeyToken.Length == 8
           && tokens.Contains(publicKeyToken, new ByteArrayEqualityComparer());
    }
}

The set of public key tokens are valid for .NET 2.0 and higher (including .NET 4.0). The ByteArrayEqualityComparer class looks like:

public class ByteArrayEqualityComparer : EqualityComparer<byte[]>
{
    public override bool Equals(byte[] x, byte[] y)
    {
        return x != null && y != null
                    && x.Length == 8 && y.Length == 8
                    && x[0] == y[0]
                    && x[1] == y[1]
                    && x[2] == y[2]
                    && x[3] == y[3]
                    && x[4] == y[4]
                    && x[5] == y[5]
                    && x[6] == y[6]
                    && x[7] == y[7];
    }

    public override int GetHashCode(byte[] obj)
    {
        return obj.GetHashCode();
    }
}

You would then use this method like:

Debug.WriteLine("Is type `string` a .NET Framework type? {0}",
   typeof(string).IsFrameworkType());
Scott Dorman
A: 

It sounds like you have a need to distinguish between types that you made yourself from everything else. Just create a custom attribute that you put on each of your types, like this:

[CustomAttribute]
struct MyDataType
{
....
}

Another option is to create an interface that all of your own custom types implement. Then it's easy to see if you need to do something special with that instance just by doing if (x is ICustom) ....

If it's possible to put them all in the same namespace or assembly, those are also easy to check with reflection.

Gabe
The problem with this approach is that you (and everyone on your team) then have to remember to add this attribute to every type ever created. This will ultimately lead to maintenance headaches when someone forgets to do this and things start to misbehave.
Scott Dorman
Scott: It's much better to rely on something under your own control than to use some heuristic that relies on MS not changing something in the next version.
Gabe
@Gabe: It still presents a major maintenance nightmare in the long run. The chances of Microsoft changing their public key tokens in later versions of the framework is slim although it could happen.
Scott Dorman
Scott: If you think it's easier to rely on an implementation detail never changing (what about .Net 5? Mono?) than to make sure that all of your classes implement the right interfaces or are in the right assembly, I suggest you reconsider how you implement coding standards.
Gabe
BTW, from the description in the question, it's not *every* type ever created; it's just the specific custom ones that need to be passed to certain methods that need the special attribute/interface/assembly/namespace.
Gabe