Определить, является ли тип объекта типом, определенным .NET Framework

Как я могу определить путем отражения, если тип объекта определяется классом в моей собственной сборке или .NET Framework?

Я не хочу указывать имя моей собственной сборки в коде, потому что она должна работать с любой сборкой и пространством имен.

Ответ 1

Где бы появились сторонние типы? Возможно, вы захотите провести различие между типами, которые, как утверждается, предоставляются Microsoft, и типами, которые этого не делают.

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");
    }
}

Конечно, любой тип может претендовать на то, чтобы быть Microsoft, которому дана эта схема, но если вы на самом деле собираетесь называть ее только своими собственными типами и фреймворками, я подозреваю, что это должно работать нормально.

В качестве альтернативы вы можете использовать токен открытого ключа сборки. Это, вероятно, будет сложнее подделать. Он полагается на Microsoft, используя общий открытый ключ для всех своих сборок, чего у них нет (согласно комментарию Мехрдада ниже). Однако вы можете легко адаптировать это решение для набора общедоступных ключей "это от Microsoft". Возможно, каким-то образом объедините оба подхода и сообщите о любых отличиях для дальнейшего осмотра...

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;
}

Ответ 2

На основании ответа Джона и комментария Мехрдада представляется, что для токена открытого ключа (из AssemblyName.FullName) используются следующие три значения: для .NET Framework предусмотрены сборки из .NET 2.0 и более поздних версий:

PublicKeyToken = b77a5c561934e089

  • mscorlib
  • System.Data​​li >
  • System.Data.OracleClient
  • System.Data.SqlXml
  • Система
  • system.runtime.remoting
  • System.Transactions
  • System.Windows.Forms
  • System.Xml
  • SMDiagnostics
  • System.Runtime.Serialization
  • System.ServiceModel
  • System.ServiceModel.Install
  • System.ServiceModel.WasHosting

PublicKeyToken = b03f5f7f11d50a3a

  • Доступность
  • 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​​li >
  • 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

Это было создано из следующего кода:

    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");
    }

Ответ 3

Как и у Mehrdad, но допускает такую ​​же проверку, даже если код выполняется в другом приложении.

obj.GetType().Assembly == typeof(SomeTypeYouKnowIsInYourAssembly).Assembly

Ответ 4

obj.GetType().Assembly == System.Reflection.Assembly.GetExecutingAssembly()

Проверяет, объявлен ли тип в текущей сборке.