13

How can I determine by reflection if the type of an object is defined by a class in my own assembly or by the .NET Framework?

I dont want to supply the name of my own assembly in code, because it should work with any assembly and namespace.

DOK
  • 32,337
  • 7
  • 60
  • 92
Mathias F
  • 15,906
  • 22
  • 89
  • 159

5 Answers5

17

Where would third-party types come in? You might want to differentiate between types which claim to be provided by Microsoft and types which don't.

using System;
using System.Linq;
using System.Reflection;

class Test
{
    static void Main()
    {
        Console.WriteLine(IsMicrosoftType(typeof(string)));
        Console.WriteLine(IsMicrosoftType(typeof(Test)));
    }

    static bool IsMicrosoftType(Type type)
    {
        object[] attrs = type.Assembly.GetCustomAttributes
            (typeof(AssemblyCompanyAttribute), false);

        return attrs.OfType<AssemblyCompanyAttribute>()
                    .Any(attr => attr.Company == "Microsoft Corporation");
    }
}

Of course, any type could claim to be a Microsoft one given this scheme, but if you're actually only going to call it on your own types and framework ones, I suspect this should work fine.

Alternatively, you could use the assembly's public key token. This is likely to be harder to fake. It relies on Microsoft using a common public key for all their assemblies, which they don't (according to Mehrdad's comment below). However, you could easily adapt this solution for a set of accepted "this is from Microsoft" public keys. Perhaps combine the two approaches somehow and report any differences for further inspection...

static bool IsMicrosoftType(Type type)
{
    AssemblyName name = type.Assembly.GetName();
    byte[] publicKeyToken = name.GetPublicKeyToken();

    return publicKeyToken != null
        && publicKeyToken.Length == 8
        && publicKeyToken[0] == 0xb7
        && publicKeyToken[1] == 0x7a
        && publicKeyToken[2] == 0x5c
        && publicKeyToken[3] == 0x56
        && publicKeyToken[4] == 0x19
        && publicKeyToken[5] == 0x34
        && publicKeyToken[6] == 0xe0
        && publicKeyToken[7] == 0x89;
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Not all Microsoft assemblies have the same public key token (even now). – Mehrdad Afshari Jun 07 '09 at 20:35
  • can't convert the byte[] publicKeyToken to string using AsciiEncoding or UnicodeEncoding What encoding is used or how to get a string representation of the PublicKeyToken – Kumar Aug 04 '09 at 13:53
  • BitConverter.ToString(bytes) will give you the hex. – Jon Skeet Aug 04 '09 at 14:05
  • 1
    If you wanted to do a string compare between the BitConverter version and an assemblies full name, you'll need to add the following, or equivalent, as BitConverter formats the value differently: BitConverter.ToString(asmName.GetPublicKeyToken()).Replace("-","").ToLower() – Nathan Sep 10 '09 at 14:23
12

Based on Jon's answer and Mehrdad's comment, it appears that the following three values are used for the public key token (from AssemblyName.FullName) for the .NET Framework provided assemblies from .NET 2.0 and later:

PublicKeyToken=b77a5c561934e089

  • mscorlib
  • System.Data
  • System.Data.OracleClient
  • System.Data.SqlXml
  • System
  • System.Runtime.Remoting
  • System.Transactions
  • System.Windows.Forms
  • System.Xml
  • SMDiagnostics
  • System.Runtime.Serialization
  • System.ServiceModel
  • System.ServiceModel.Install
  • System.ServiceModel.WasHosting

PublicKeyToken=b03f5f7f11d50a3a

  • Accessibility
  • AspNetMMCExt
  • cscompmgd
  • CustomMarshalers
  • IEExecRemote
  • IEHost
  • IIEHost
  • ISymWrapper
  • Microsoft.Build.Conversion
  • Microsoft.Build.Engine
  • Microsoft.Build.Framework
  • Microsoft.Build.Tasks
  • Microsoft.Build.Utilities
  • Microsoft.JScript
  • Microsoft.VisualBasic.Compatibility.Data
  • Microsoft.VisualBasic.Compatibility
  • Microsoft.VisualBasic
  • Microsoft.VisualBasic.Vsa
  • Microsoft.VisualC
  • Microsoft.Vsa
  • Microsoft.Vsa.Vb.CodeDOMProcessor
  • Microsoft_VsaVb
  • sysglobl
  • System.Configuration
  • System.Configuration.Install
  • System.Deployment
  • System.Design
  • System.DirectoryServices
  • System.DirectoryServices.Protocols
  • System.Drawing.Design
  • System.Drawing
  • System.EnterpriseServices
  • System.Management
  • System.Messaging
  • System.Runtime.Serialization.Formatters.Soap
  • System.Security
  • System.ServiceProcess
  • System.Web
  • System.Web.Mobile
  • System.Web.RegularExpressions
  • System.Web.Services
  • Microsoft.Transactions.Bridge
  • Microsoft.Transactions.Bridge.Dtc
  • Microsoft.Build.Tasks.v3.5
  • Microsoft.CompactFramework.Build.Tasks
  • Microsoft.Data.Entity.Build.Tasks
  • Microsoft.VisualC.STLCLR
  • Sentinel.v3.5Client

PublicKeyToken=31bf3856ad364e35

  • PresentationCFFRasterizer
  • PresentationUI

This was generated from the following code:

    private void PrintAssemblyInfo(string fullName)
    {
        string[] parts = fullName.Split(',');
        Console.WriteLine(" - {0}, {1}", parts[0], parts[3]);
    }

    private void GenerateInfo(string path)
    {
        foreach (var file in Directory.GetFiles(path, 
           "*.dll",
           SearchOption.AllDirectories))
        {
            try
            {
                Assembly assembly = Assembly.ReflectionOnlyLoadFrom(file);
                PrintAssemblyInfo(assembly.GetName().FullName);
            }
            catch { }
        }
    }

    private void GenerateInfo()
    {
        GenerateInfo(@"C:\Windows\Microsoft.NET\Framework\v2.0.50727");
        GenerateInfo(@"C:\Windows\Microsoft.NET\Framework\v3.0");
        GenerateInfo(@"C:\Windows\Microsoft.NET\Framework\v3.5");
    }
Scott Dorman
  • 42,236
  • 12
  • 79
  • 110
8

Similar to Mehrdad's answer, but allows for the same check even if the code is executing in some other application.

obj.GetType().Assembly == typeof(SomeTypeYouKnowIsInYourAssembly).Assembly
AgileJon
  • 53,070
  • 5
  • 41
  • 38
7
obj.GetType().Assembly == System.Reflection.Assembly.GetExecutingAssembly()

Checks if the type is declared in the current assembly.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
0

Here is a more modern, circa 2022 version of Scott Dorman's solution, that gives you the final list of public key tokens:

using System.Reflection;

new PublicKeyExplorer().GenerateInfo();

class PublicKeyExplorer
{
private string GetPublicKeyToken(string fullName)
{
    string[] parts = fullName.Split(',');
    return parts[3];
}

private void GenerateInfo(string path, HashSet<string> tokens)
{
    foreach (var file in Directory.GetFiles(path,
                 "*.dll",
                 SearchOption.AllDirectories))
    {
        try
        {
            Assembly assembly = Assembly.LoadFrom(file);
            tokens.Add(GetPublicKeyToken(assembly.GetName().FullName));
        }
        catch (Exception e)
        {
        }
    }
}

public void GenerateInfo()
{
    var tokens = new HashSet<string>();
    GenerateInfo(@"C:\Program Files\dotnet\sdk\3.1.425\", tokens);
    GenerateInfo(@"C:\Program Files\dotnet\sdk\5.0.408\", tokens);
    GenerateInfo(@"C:\Program Files\dotnet\sdk\6.0.401\", tokens);
    GenerateInfo(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\", tokens);
    GenerateInfo(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\", tokens);

    foreach (var publicKeyToken in tokens)
    {
        Console.WriteLine(publicKeyToken);
    }
}

}

Omer Raviv
  • 11,409
  • 5
  • 43
  • 82