Я хочу отчетливо определить, имеет ли тип, который я имею, пользовательский тип класса (MyClass) или один обеспеченный Платформой (Система. Строка).
Есть ли какой-либо путь в отражении, что я могу отличить свой тип класса от system.string или другой Основы, служившей типы?
Единственный способ безопасно проверить, является ли тип частью сборки, - это проверить полное имя сборки, которое содержит ее имя, версию, язык и региональные параметры и открытый ключ (если он подписан). Все библиотеки базовых классов .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, чтобы просто проверить токен открытого ключа. Это зависит от ваших потребностей.
Если вы просто хотите различать MyClass
и строку
, то вы можете проверить эти типы напрямую:
Type typeToTest = GetTypeFromSomewhere();
if (typeToTest == typeof(MyClass))
MyClassAction();
else if (typeToTest == typeof(string))
StringAction();
else
NotMyClassOrString();
Если вам нужна более общая проверка того, является ли данный type - это тип фреймворка, тогда вы можете проверить, принадлежит ли он пространству имен 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));
Не все классы фреймворка начинаются в пространстве имен 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, которое не является классом фреймворка).
Редактировать
Также, в дополнение к приведенному выше тесту, не помешает проверить, что тип загружен из кэша глобальной сборки:
typeof(MyType).Assembly.GlobalAssemblyCache
Вы можете проверить сборку, в которой объявлен тип.
object.GetType().Assembly