Type.IsSubclassOf () не работает в доменах приложений? - PullRequest
6 голосов
/ 21 января 2009

У меня проблемы с кодом:

private class ClientPluginLoader : MarshalByRefObject
{
    public bool IsPluginAssembly(string filename)
    {
        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomainReflectionOnlyAssemblyResolve);

        Assembly asm = Assembly.ReflectionOnlyLoadFrom(filename);

        Type[] types = asm.GetTypes();
        foreach (Type type in types)
        {
            if (type.IsSubclassOf(typeof(ClientPlugin)))
            {
                return true;
            }
        }

        return false;
    }
}

Код вызывается через прокси, который я создал через CreateInstanceFromAndUnwrap () моего домена приложения. Это означает, что IsPluginAssembly () выполняется в контексте моего пользовательского домена приложения.

Проблема в том, что вызов IsSubclassOf () всегда возвращает false, даже если он ИМХО возвращает true. «Тип», о котором идет речь, действительно наследуется от ClientPlugin - в этом нет никаких сомнений.

ClientPlugin определен в другой частной сборке, которую я решаю вручную, как видно из фрагмента кода выше.

Я установил точку останова в строке if (type.IsSubclassOf(...)) и подтвердил, что это выражение ложно:

type.BaseType == typeof(ClientPlugin)

С другой стороны, это выражение верно:

type.BaseType.FullName == typeof(ClientPlugin).FullName

Как это возможно? Что происходит?

ОБНОВЛЕНИЕ: Кент Бугаарт указал мне правильное направление. Я немного поискал в Интернете и наткнулся на этот пост в блоге. Похоже, мне придется разрешить конфликты Load / LoadFrom / ReflectionOnlyLoadFrom, чтобы эта работа работала.

Ответы [ 2 ]

7 голосов
/ 21 января 2009

Это связано с загрузкой в ​​другом контексте. Способ загрузки сборки (Load / LoadFrom / ReflectionOnlyLoad) определяет, в какой контекст она загружена. Этот простой пример также демонстрирует проблему:

using System;
using System.Reflection;

class Foo
{
    public static void Main()
    {
        var type = typeof(Foo);
        var reflectionLoadType = Assembly.ReflectionOnlyLoad("ConsoleApplication1").GetType("Foo");
        Console.WriteLine(type == reflectionLoadType);  //false
        Console.WriteLine(type.Equals(reflectionLoadType));  //false

        Console.WriteLine("DONE");
        Console.ReadKey();
    }
}

См. здесь для получения дополнительной информации.

2 голосов
/ 21 января 2009

У меня была похожая проблема. У меня также была эта архитектура - .DLL, который содержит базовый класс ClientPlugin; несколько плагинов, которые ссылаются на этот .DLL; и основное приложение, которое также ссылается на этот .DLL. Проблема заключалась в том, что файл .DLL с базовым классом ClientPlugin был скопирован в две папки - и папку плагинов, и основную папку приложения. Таким образом, он дважды загружался в мой AppDomain (плагины также загружали его косвенно). И когда основное приложение пыталось сделать магию типа отражения, это не удалось, потому что было два экземпляра типа ClientPlugin.

Хотя я не думаю, что это именно ваш случай, здесь все же есть урок - если дважды загрузить .DLL, типы также будут дублироваться. В вашем случае я бы заподозрил либо отдельные AppDomains, либо «ReflectionOnlyLoad», потому что тогда .DLL загружается как-то иначе.

...