Почему System.Type.GetType ("Xyz") возвращает ноль, если typeof (Xyz) существует? - PullRequest
18 голосов
/ 21 сентября 2010

Я столкнулся со странным поведением в моем (огромном) проекте .NET 4.В какой-то момент в коде я имею в виду полностью определенный тип, скажем:

System.Type type = typeof (Foo.Bar.Xyz);

позже я делаю это:

System.Type type = System.Type.GetType ("Foo.Bar.Xyz");

и я получаю обратно null,Я не могу понять, почему это происходит, потому что мое имя типа является правильным, и я проверил с другими типами, и они разрешены правильно.Кроме того, следующий запрос LINQ находит тип:

var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
            from assemblyType in assembly.GetTypes ()
            where assemblyType.FullName == typeName
            select assemblyType;

System.Type type = types.FirstOrDefault ();

Существуют ли причины, по которым System.Type.GetType может завершиться неудачей?

Мне, наконец, пришлось прибегнуть к этому куску кода вместо GetType:

System.Type MyGetType(string typeName)
{
    System.Type type = System.Type.GetType (typeName);

    if (type == null)
    {
        var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
                    from assemblyType in assembly.GetTypes ()
                    where assemblyType.FullName == typeName
                    select assemblyType;

        type = types.FirstOrDefault ();
    }

    return type;
}

Ответы [ 4 ]

27 голосов
/ 21 сентября 2010

Если вы просто дадите имя класса (которое, конечно, требует , должно быть полностью квалифицировано в терминах пространства имен), Type.GetType(string) будет искать только текущую исполняемую сборку и mscorlib.Если вы хотите получить типы из любой другой сборки, вам нужно указать абсолютно полное имя, включая информацию о сборке.Как говорит Франсуа, Type.AssemblyQualifiedName - это хороший способ увидеть это.Вот пример:

using System;
using System.Windows.Forms;

class Test
{
    static void Main()
    {
        string name = typeof(Form).AssemblyQualifiedName;
        Console.WriteLine(name);

        Type type = Type.GetType(name);
        Console.WriteLine(type);
    }
}

Вывод:

System.Windows.Forms.Form, System.Windows.Forms, версия = 4.0.0.0, культура = нейтральная,
PublicKeyToken = b77a5c561934e089
System.Windows.Forms.Form

Обратите внимание, что если вы используете сборку со строгим именем (например, Form в этом случае), вы должны включить all информация о сборке - версия, токен открытого ключа и т. Д.

Если вы используете сборку без строгого имени, это проще - что-то вроде:

Foo.Bar.Baz, MyCompany.MyAssembly

длятип с именем Baz в пространстве имен Foo.Bar, в сборке MyCompany.MyAssembly.Обратите внимание на отсутствие «.dll» в конце - это часть имени файла, но не имя сборки.

Вы также должны знать о различиях между именами C # и именами CLR для таких вещей, как вложенные классы идженерики.Например, typeof(List<>.Enumerator) имеет имя System.Collections.Generic.List`1+Enumerator[T].Со стороны обобщения сложно работать, но бит вложенного типа прост - он просто представлен знаком «+» вместо «.»вы бы использовали в C #.

4 голосов
/ 22 сентября 2010

Из документации MSDN (мой акцент):

Если typeName включает пространство имен, но не имя сборки, этот метод выполняет поиск только сборки вызывающего объекта и Mscorlib.dll в этом порядке. Если typeName полностью определено с частичным или полным именем сборки, этот метод выполняет поиск в указанной сборке. Если сборка имеет строгое имя, необходимо указать полное имя сборки.

4 голосов
/ 21 сентября 2010

Насколько я знаю, GetType ищет "Xyz" в сборке с именем Foo.Bar.dll, и я предполагаю, что ее не существует.

GetType полагается на передачу точного пути к Xyzв сборе.Сборка и пространство имен не должны быть связаны между собой.

Попробуйте System.Type type = System.Type.GetType(typeof(Foo.Bar.Xyz).AssemblyQualifiedName) и посмотрите, работает ли это.

Причина, по которой вы нашли это на примере LINQ, заключается в том, что вы используете GetAssembliesкоторый получает сборки, которые были загружены в текущий контекст выполнения, и, таким образом, содержит сведения, необходимые для поиска всех типов в сборках.

1 голос
/ 12 января 2015

Я просто наткнулся на похожую проблему и хочу оставить это здесь

Прежде всего, вы можете указать AssemblyName в строке

var type = System.Type.GetType("Foo.Bar.Xyz, Assembly.Name");

Однако это работает только для сборок без строгого имени. Объяснение уже есть в ответе Саймонса If the assembly has a strong name, a complete assembly name is required.

Моя проблема заключалась в том, что мне пришлось разрешить System.Dictionary<?,?> из строки во время выполнения. Для Dictionary<int, string> это может быть легко, но как насчет Dictionary<int, Image>?

это приведет к

var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]]";

Но я не хочу писать строгое имя. Особенно потому, что я не хочу включать версии, так как я планирую ориентироваться на несколько фреймворков с моим кодом.

Так вот мое решение

    privat statice void Main()
    {
        var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing]]";
        var type = Type.GetType(typeName, ResolveAssembly, ResolveType);
    }

    private static Assembly ResolveAssembly(AssemblyName assemblyName)
    {
        if (assemblyName.Name.Equals(assemblyName.FullName))
            return Assembly.LoadWithPartialName(assemblyName.Name);
        return Assembly.Load(assemblyName);
    }

    private static Type ResolveType(Assembly assembly, string typeName, bool ignoreCase)
    {
        return assembly != null
            ? assembly.GetType(typeName, false, ignoreCase)
            : Type.GetType(typeName, false, ignoreCase);
    }

Type.GetType(...) имеет перегрузку, которая принимает функцию для сборки и определения типа, что в аккуратном виде. Assembly.LoadWithPartialName устарело, но если оно будет удалено в будущем, я мог бы подумать о замене (перебрать все сборки в текущем домене приложения и сравнить частичные имена).

...