Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Динамическое создание типов из DLL в C#  (Прочитано 7843 раз)
0 Пользователей и 1 Гость смотрят эту тему.
USBLexus
Опытный

ru
Offline Offline
Пол: Мужской
Кот рыжий


« : 19-05-2010 11:00 » 

Здравствуйте форумчане! Вот зашел сегодня в тупик:

Есть интерфейс IShellSpecific, есть DLL в которой определен класс унаследованный от интерфейса IShellSpecific

Код:
   public class ShellSpecific : IShellSpecific
    {
        public ShellSpecific()
        {
            
        }

        public string ApplicationName
        {
            get { throw new NotImplementedException(); }
        }

        public XtraForm AboutForm
        {
            get { throw new NotImplementedException(); }
        }
   }

Загружаю эту библиотеку, экземпляр класса ShellSpecific  создается но к типу IShellSpecific не приводится! Причем если написать ShellSpecific is IShellSpecific возвращает true, но приведение вылетает с ошибкой что тип к интерфейсу преобразован быть не может, IsAssignableFrom возвращает false, вот код:

Код:
               Assembly assembly = Assembly.LoadFrom(dllFullFileName);
                Type[] types = assembly.GetExportedTypes();
                foreach (Type type in types)
                {
                    //Загрузка спецификации оболочки
                    if (typeof(IShellSpecific).IsAssignableFrom(type))
                    {
                        object shellSpecific = Activator.CreateInstance(type);
                        IShellSpecific iface = shellSpecific as IShellSpecific;
                        int t = 1;
                    }
                }

Как такое может быть??? Не надо
« Последнее редактирование: 19-05-2010 17:45 от RXL » Записан

#define QUESTION(b) (2*b)||(!(2*b)) (c) William Shakespeare
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 19-05-2010 11:44 » 

USBLexus, а зачем все эти танцы с бубном?

Код: (Text) C#.NET
IShellSpecific shellSpecific = new ShellSpecific();
Так работает?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
USBLexus
Опытный

ru
Offline Offline
Пол: Мужской
Кот рыжий


« Ответ #2 : 19-05-2010 16:33 » 

USBLexus, а зачем все эти танцы с бубном?

Все эти танцы с бубном потому что динамически подключаемая библиотека может содержать любые классы и иметь любое имя и путь, единственное что я о них знаю, это то что они реализуют интерфейс IShellSpecific

Внутри класса ShellSpecific данный код работает:
IShellSpecific shellSpecific = new ShellSpecific();
Записан

#define QUESTION(b) (2*b)||(!(2*b)) (c) William Shakespeare
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 19-05-2010 19:50 » 

USBLexus, я не вижу никаких проблем сделать то, что ты делаешь.

Итак, заводим одну общую сборку Common.dll, в которой присутствует интерфейс:
Код: (Text) C#.NET
namespace Common
{
    public interface ITest
    {
    }
}

Затем заводим сборку для динамической загрузки TestLib.dll, в которой существуют какие-то неизвестные классы, реализующие интерфейс общей сборки (естественно, эта сборка ссылается на Common.dll).
Код: (Text) C#.NET
using Common;

namespace DynamicLoadingTypes
{
    public class Test: ITest
    {
    }

    public class Test1 : Test
    {
    }
}

Наконец, пишем тестовое приложение TestApp.exe, которое ссылается на Common.dll, а TestLib.dll загружает динамически. Внутри него пишем тест, который перебирает типы загруженной сборки на совместимость с интерфейсом и, если совместимость установлена, создаёт экземпляры и приводит их к интерфейсу:
Код: (Text) C#.NET
        static IEnumerable<ITest> CreateInstances(string assemblyPath)
        {
            string iTestName = typeof(ITest).ToString();
            Type[] defaultConstructorParametersTypes = new Type[0];
            object[] defaultConstructorParameters = new object[0];
            Assembly assembly = Assembly.LoadFile(assemblyPath);
            foreach (Type type in assembly.GetTypes())
            {
                if (type.GetInterface(iTestName) != null)
                {
                    ConstructorInfo defaultConstructor = type.GetConstructor(defaultConstructorParametersTypes);
                    object instance = defaultConstructor.Invoke(defaultConstructorParameters);
                    yield return instance as ITest;
                }
            }
        }

        static void Test(string assemblyName)
        {
            foreach (ITest instance in CreateInstances(assemblyName))
            {
                Console.WriteLine(instance.ToString());
            }
        }
И убеждаемся, что всё работает.
« Последнее редактирование: 19-05-2010 19:52 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
USBLexus
Опытный

ru
Offline Offline
Пол: Мужской
Кот рыжий


« Ответ #4 : 20-05-2010 08:02 » 

Именно так у меня все и сделано, а как по другому то? Не работает, говорю же
Есть у меня одно подозрение что библиотека Common.dll одна и таже но берется из 2х разных мест может в этом проблема, сегодня проверить возможности нет, гляну завтра
« Последнее редактирование: 20-05-2010 08:04 от USBLexus » Записан

#define QUESTION(b) (2*b)||(!(2*b)) (c) William Shakespeare
USBLexus
Опытный

ru
Offline Offline
Пол: Мужской
Кот рыжий


« Ответ #5 : 21-05-2010 09:21 » 

Есть у меня одно подозрение что библиотека Common.dll одна и таже но берется из 2х разных мест может в этом проблема, сегодня проверить возможности нет, гляну завтра

Да, дело было именно в этом
« Последнее редактирование: 21-05-2010 09:34 от USBLexus » Записан

#define QUESTION(b) (2*b)||(!(2*b)) (c) William Shakespeare
Malaja
Команда клуба

de
Offline Offline
Пол: Женский

« Ответ #6 : 28-05-2010 15:30 » 

USBLexus,

как раз разбираюсь с темой "reflection".
Попробовала твой пример, немного усложнив (как оказалось) - внесла в интерфейс функцию
Код:
  void testFunc_ICommon();

Затем в классе Test реализовала:
Код:

 public void testFunc_ICommon()
 {
   Console.WriteLine("TestICommon::testFunc_ICommon() was called >>>>>>>>>>>");
 }

А в классе Test1 перегрузила:
Код:
new public void testFunc_ICommon()
 {
Console.WriteLine("TestICommon::testFunc_ICommon_2() was called >>>>>>>>>>>");
 }

Ну и напоследок для теста в функции Test() добавила:
Код:
  instance.testFunc_ICommon();
       
После чего возник вопрос:
почему при получении инстанции классе Test1 вызывается функция класса Test (т.е. перегрузка не срабатывает)?
Что тут криво?
Записан

холоднокровней, Маня, Ви не на работе
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 29-05-2010 08:50 » 

Malaja, потому что функцию нужно объявить виртуальной, и перегружать не через new, а через override.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Malaja
Команда клуба

de
Offline Offline
Пол: Женский

« Ответ #8 : 31-05-2010 08:02 » 

Дим,
спасибо!
Я ступила - я сначала ее сделала виртуальной, но вместо override написала сразу new. А когда оно не сработало, вообще убрала virtual...
Все-таки c++ и c# "немного" отличаются... Воистину - "учите матчасть" Ага
Записан

холоднокровней, Маня, Ви не на работе
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines