How do I determine if System.Type is a custom type or a Framework type?
Asked Answered
M

6

14

I want to distinctly determine if the type that I have is of custom class type (MyClass) or one provided by the Framework (System.String).

Is there any way in reflection that I can distinguish my class type from system.string or other Framework provided types?

Mond answered 4/7, 2010 at 14:10 Comment(0)
X
7

The only way to safely check if a type is part of an assembly is to check the assembly's fully qualified name which contains its name, version, culture and public key (if signed). All .Net base class libraries (BCL) are signed by microsoft using their private keys. This makes it almost impossible for anyone else to create an assembly with same fully qualified name as a base class library.

//add more .Net BCL names as necessary
var systemNames = new HashSet<string>
{
"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
};

var isSystemType = systemNames.Contains(objToTest.GetType().Assembly.FullName); 

A slightly less brittle solution is to use the AssemblyName class and skip the version number/culture check. This of course assumes the public key doesn't change between versions.

//add more .Net BCL names as necessary
var systemNames = new List<AssemblyName>
{
new AssemblyName ("mscorlib, Version=4.0.0.0, Culture=neutral, " +
                  "PublicKeyToken=b77a5c561934e089"),
new AssemblyName ("System.Core, Version=4.0.0.0, Culture=neutral, "+
                  "PublicKeyToken=b77a5c561934e089")
};

var obj = GetObjectToTest();

var objAN = new AssemblyName(obj.GetType().Assembly.FullName);

bool isSystemType = systemNames.Any(
        n =>  n.Name == objAN.Name 
           && n.GetPublicKeyToken().SequenceEqual(objAN.GetPublicKeyToken()));

Most of the BCL have been signed with the same key but not all. You could use the AssemblyName class to just check the public key token. It depends on your needs.

Xantha answered 4/7, 2010 at 23:42 Comment(0)
U
6

If you simply want to distinguish between MyClass and string then you can check for those types directly:

Type typeToTest = GetTypeFromSomewhere();

if (typeToTest == typeof(MyClass))
    MyClassAction();
else if (typeToTest == typeof(string))
    StringAction();
else
    NotMyClassOrString();

If you need a more general check for whether or not a given type is a framework type then you could check whether it belongs to the System namespace:

// create an array of the various public key tokens used by system assemblies
byte[][] systemTokens =
    {
        typeof(System.Object)
            .Assembly.GetName().GetPublicKeyToken(),  // B7 7A 5C 56 19 34 E0 89
        typeof(System.Web.HttpRequest)
            .Assembly.GetName().GetPublicKeyToken(),  // B0 3F 5F 7F 11 D5 0A 3A 
        typeof(System.Workflow.Runtime.WorkflowStatus)
            .Assembly.GetName().GetPublicKeyToken()   // 31 BF 38 56 AD 36 4E 35 
    };

Type typeToTest = GetTypeFromSomewhere();

string ns = typeToTest.Namespace;
byte[] token = typeToTest.Assembly.GetName().GetPublicKeyToken();

bool isSystemType = ((ns == "System") || ns.StartsWith("System."))
                    && systemTokens.Any(t => t.SequenceEqual(token));
Understand answered 4/7, 2010 at 15:33 Comment(4)
Not really bulletproof, forinstance if the namespace is called "SystemUtil" ;)Thunderclap
@thomas: I realised that soon after posting but was called away before I could edit. Now fixed.Understand
I'm pretty sure you can actually write your own assembly and make the namespace System.[something]... I'm not a big fan of doing this, but I know some open-source projects do -- e.g., System.Data.SQLite, System.Drawing.Html.Partly
@Dan: That's very true, although it's also a pretty bad practice. I've edited to include a check against the assembly's PublicKeyToken to ensure that it's a true system type. Of course, if you only want to check that it's a core system type then you could just do if (typeToTest.Assembly == typeof(int).Assembly), but that would exclude members of the wider System.* namespace (for example, XmlDocument). I guess it really depends on what exactly the OP is trying to achieve.Understand
O
4

You can check the Assembly in which the type is declared.

object.GetType().Assembly
Ogle answered 4/7, 2010 at 14:11 Comment(1)
So the question then is: how to know that an assembly is part of the .NET framework?Seabrooke
S
1

Check if the assembly belongs to the CLR library:

myType.Module.ScopeName == "CommonLanguageRuntimeLibrary"

as explained here.

Siret answered 22/1, 2017 at 16:35 Comment(0)
C
0

Not all framework classes start in the System namespace (they can also be Microsoft etc).

As such, you could probably compare the location of a known framework class with that of the type that you are testing such as:

  if (String.CompareOrdinal(
        Path.GetDirectoryName(typeof(String).Assembly.Location), 
        Path.GetDirectoryName(typeof(MyType).Assembly.Location)
      ) == 0)
  {
    //Framework Type
  }
  else
  {
    //3rd Party DLL
  }

Not the greatest solution; but safer than just testing if the namespace starts with System (I could create a namespace that starts with System that isn't a framework class).

Edit

Also, in addition to the above test, it wouldn't hurt to verify that the type is loaded from the Global Assembly Cache:

typeof(MyType).Assembly.GlobalAssemblyCache
Chericheria answered 4/7, 2010 at 17:49 Comment(2)
As far as I'm aware, the BCL consists only of the System.* namespaces. The Microsoft.* namespaces are a superset of the BCL -- sometimes known as the FCL -- and aren't part of the ECMA CLI standard. en.wikipedia.org/wiki/Base_Class_LibraryUnderstand
@LukeH: Really good point. The important point I was going for was to not rely on the namespace starting with System. And as other solutions have shown, being explict is always the best bet; this is a "poor man's" check that I thought I would throw up just in case.Chericheria
T
0

My solution, if it can help :

private static readonly string _RuntimeDirectory =
    System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
public static bool IsSystem(this Type type)
    => type.Assembly.Location.StartsWith(_RuntimeDirectory);
Talent answered 18/5, 2021 at 18:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.