Как определить, является ли System.Type пользовательским типом или типом Framework? - PullRequest
11 голосов
/ 04 июля 2010

Я хочу четко определить, относится ли мой тип к пользовательскому типу класса (MyClass) или к типу, предоставленному платформой (System.String).

Есть ли способ отразить, что я могу отличить мой тип класса от system.string или других типов, предоставляемых Framework?

Ответы [ 5 ]

7 голосов
/ 05 июля 2010

Единственный способ безопасно проверить, является ли тип частью сборки, - это проверить полное имя сборки, которое содержит ее имя, версию, культуру и открытый ключ (если подписано). Все библиотеки базовых классов .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, чтобы просто проверить токен открытого ключа. Это зависит от ваших потребностей.

5 голосов
/ 04 июля 2010

Если вы просто хотите различить 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));
4 голосов
/ 04 июля 2010

Вы можете проверить сборку, в которой объявлен тип.

object.GetType().Assembly
1 голос
/ 22 января 2017

Проверьте, принадлежит ли сборка библиотеке CLR:

myType.Module.ScopeName == "CommonLanguageRuntimeLibrary"

, как объяснено здесь .

0 голосов
/ 04 июля 2010

Не все каркасные классы начинаются в пространстве имен 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...