Как определить, является ли System.Type настраиваемым типом или типом Framework?
Я хочу четко определить, имеет ли тип, который у меня есть, тип пользовательского класса (MyClass) или один, предоставленный Framework (System.String).
Есть ли какой-либо способ отражения, что я могу отличить свой тип класса от system.string или других типов, предоставляемых Framework?
Ответы
Ответ 1
Единственный способ безопасно проверить, является ли тип частью сборки, - проверить полное имя сборки, которое содержит его имя, версию, культуру и открытый ключ (если они подписаны). Все библиотеки базового класса .Net(BCL) подписываются microsoft с использованием их секретных ключей. Это делает почти невозможным для кого-либо еще создать сборку с таким же полным именем, как библиотека базового класса.
//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);
Немного менее хрупкое решение заключается в использовании AssemblyName и пропустить номер версии/проверку культуры. Это, конечно, предполагает, что открытый ключ не изменяется между версиями.
//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()));
Большинство BCL были подписаны с одним и тем же ключом, но не со всеми. Вы можете использовать класс AssemblyName, чтобы просто проверить токен открытого ключа. Это зависит от ваших потребностей.
Ответ 2
Если вы просто хотите различать MyClass
и string
, вы можете напрямую проверить эти типы:
Type typeToTest = GetTypeFromSomewhere();
if (typeToTest == typeof(MyClass))
MyClassAction();
else if (typeToTest == typeof(string))
StringAction();
else
NotMyClassOrString();
Если вам нужна более общая проверка того, является ли данный тип типом структуры, то вы можете проверить, принадлежит ли это пространству имен System
:
// 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));
Ответ 3
Вы можете проверить сборку, в которой объявлен тип.
object.GetType().Assembly
Ответ 4
Проверьте, принадлежит ли сборка библиотеке CLR:
myType.Module.ScopeName == "CommonLanguageRuntimeLibrary"
как описано здесь.
Ответ 5
Не все классы классов начинаются в пространстве имен System (они также могут быть Microsoft и т.д.).
Таким образом, вы, вероятно, можете сравнить местоположение известного класса рамки с типом тестируемого вами типа, например:
if (String.CompareOrdinal(
Path.GetDirectoryName(typeof(String).Assembly.Location),
Path.GetDirectoryName(typeof(MyType).Assembly.Location)
) == 0)
{
//Framework Type
}
else
{
//3rd Party DLL
}
Не самое большое решение; но безопаснее, чем просто тестировать, если пространство имен начинается с System (я мог бы создать пространство имен, которое начинается с System, который не является классом инфраструктуры).
Edit
Кроме того, в дополнение к вышеуказанному тесту, не помешает проверить, что тип загружен из глобального сборочного кэша:
typeof(MyType).Assembly.GlobalAssemblyCache