Определить, является ли тип объекта типом, определенным .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.Datali >
- 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.Datali >
- 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()
Проверяет, объявлен ли тип в текущей сборке.