Как работает Type.GetType, когда вы получаете частично квалифицированное имя типа?
Во многих местах я встречаю частично квалифицированные имена типов формы FullTypeName, AssemblyName
, то есть как Type.AssemblyQualifiedName
, только без квалификаторов версии, культуры и publicKeyToken.
Мой вопрос в том, как можно преобразовать его в соответствующий Type
в минимальные усилия? Я думал, что Type.GetType
выполняет эту работу, но, увы, это не так. Следующий код, например, возвращает null
:
Type.GetType("System.Net.Sockets.SocketException, System");
Конечно, если я укажу полное имя, оно действительно работает:
Type.GetType("System.Net.Sockets.SocketException, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
Большое спасибо.
Ответы
Ответ 1
Если DLL файл в нем еще не загружен в домен приложения (например, вы его использовали), вам нужен полный путь, как этот, если он уже загружен, он может найти его с более короткой версией.
Чтобы ответить на ваш вопрос: вторая версия всегда работает, придерживайтесь ее, и у вас есть один способ беспокоиться.
Ответ 2
Если сборка была загружена в текущий домен, тогда обычно работает код ниже:
public static Type GetTypeEx(string fullTypeName)
{
return Type.GetType(fullTypeName) ??
AppDomain.CurrentDomain.GetAssemblies()
.Select(a => a.GetType(fullTypeName))
.FirstOrDefault(t => t != null);
}
Вы можете использовать его так:
Type t = GetTypeEx("System.Net.Sockets.SocketException");
Ответ 3
Код, работающий с короткой формой:
Assembly a = Assembly.LoadWithPartialName(assemblyName);
Type t = a.GetType(typeName);
но LoadWithPartialName устарело, поэтому я думаю, вы должны придерживаться длинной формы.
Ответ 4
Пройдя аналогичную проблему с некоторым устаревшим кодом, я не думаю, что первое утверждение в принятом ответе правильное. Не имеет значения, загружена ли сборка.
Согласно документации, Type.GetType(строка) требует AssemblyQualifiedName, если только этот тип не находится в выполняющейся в настоящее время сборке или в mscorlib, и в этом случае требуется имя типа с именем пространства имен.
Обратите внимание, что AssemblyQualifiedName включает полное DisplayName сборки типа (с ключом версии, культуры и открытого ключа).
Краткая версия не будет работать, если вы не перехватите неудачную загрузку типа с помощью AssemblyResolver (на самом деле это было связано с моей проблемой, маскирование другой проблемы).
Ответ 5
Правда, Type.GetType(string) действительно требует AssemblyCualifiedName. Это может быть во многих формах:
MyNS.MyType, MyAssembly, Version=x.x.x.x, Culture=xxx, PublicKeyToken=XXXXXXXXXX
Также допустимы следующие: AssemblyQualifiedNames:
MyNS.MyType, MyAssembly, Version=x.x, Culture=xxx, PublicKeyToken=XXXXXXXXXX
MyNS.MyType, MyAssembly, Culture=xxx, PublicKeyToken=XXXXXXXXXX
MyNS.MyType, MyAssembly, PublicKeyToken=XXXXXXXXXX
MyNS.MyType, MyAssembly
Для подписанной сборки минимальный размер, необходимый для FullyQualifiedAssemblyName:
MyNS.MyType, MyAssembly, PublicKeyToken=XXXXXXXXXX
Для неподписанной сборки минимальный размер, необходимый для FullyQualifiedAssemblyName:
MyNS.MyType, MyAssembly
Не нужно, чтобы все "ручные махания" выполнялись в фрагментах кода, предоставленных другими пользователями. Убедитесь, что ваши имена типов настроены правильно, и вы можете получить доступ к своим типам (и загружать сборки динамически) с высокой степенью гибкости. Я делаю это регулярно.
В примере OP с использованием:
Type.GetType("System.Net.Sockets.SocketException, System")
Причиной отказа было отсутствие PublicKeyToken. Все сборки .Net FW подписаны и, следовательно, требуют, чтобы PublicKeyToken разрешил имя Ассамблеи. Было бы выполнено следующее:
Type.GetType("System.Net.Sockets.SocketException, System, PublicKeyToken=b77a5c561934e089")