Приведение типа
От: Павел Киселев  
Дата: 16.12.03 12:58
Оценка:
Имею следующую проблему.

Есть некий интерфейс и класс унаследованный от него:

namespace LIB_TEST
{
    public interface ITest
    {
        void Init();
    }
    
    public class TestDLL : ITest
    {
        public TestDLL()
        {
        }
        
        public void Init()
        {
        }
    }
}

В другом модуле создаю этот класс посредствам System.Activator, пердварительно проверив наличие нужного мне интерфейса
System.Reflection.Assembly CurrentAssembly = System.Reflection.Assembly.LoadFrom("C:\\LIB_TEST.dll");

object My_object;
foreach (System.Type CurType in CurrentAssembly.GetTypes())
{
    if (CurType.GetInterface("LIB_TEST.ITest") != null)
    {
        My_object = System.Activator.CreateInstance(CurType);
    };
};

Далее пытаюсь получить требуемый интерфейс ITest
LIB_TEST.ITest My_Test = (LIB_TEST.ITest)My_object;
My_Test.Init();

Но почему-то при приведении типа от object возникает исключение System.InvalidCastException - "Specified cast is not valid."

Подскажите что делаю не так???
Зарание спасибо.
Re: Приведение типа
От: Dr_Sh0ck Беларусь  
Дата: 16.12.03 13:03
Оценка: 18 (1) +1
Здравствуйте, Павел Киселев, Вы писали:

ПК>Имею следующую проблему.


ПК>Есть некий интерфейс и класс унаследованный от него:


Мвленькая поправка: не _унаследованный_, а _реализующий_

ПК>Далее пытаюсь получить требуемый интерфейс ITest

ПК>
ПК>LIB_TEST.ITest My_Test = (LIB_TEST.ITest)My_object;
ПК>My_Test.Init();
ПК>

ПК>Но почему-то при приведении типа от object возникает исключение System.InvalidCastException - "Specified cast is not valid."

ИМХО тут надо было делать не так. Лучше проверять наличие интерфейса не по текстовуму имени, а по типу. А причина может быть в том, что ты просто объявил два разных интрефейса с одним и тем же именем — ITest в двух этих модулях?
Просто из твоего постинга не совсем понятно — есть ли взаимосвязь между модулями на уровне метаданных.
Do not fake yourself ;)
ICQ#: 198114726
Re[2]: Приведение типа
От: Павел Киселев  
Дата: 16.12.03 13:29
Оценка:
Здравствуйте, Dr_Sh0ck, Вы писали:


D_S>ИМХО тут надо было делать не так. Лучше проверять наличие интерфейса не по текстовуму имени, а по типу.


Да дело то в том, что
My_object = System.Activator.CreateInstance(CurType);

выполняется без проблем, т.е. конструктор данного класа вызывается

D_S>А причина может быть в том, что ты просто объявил два разных интрефейса с одним и тем же именем — ITest в двух этих модулях?

Специально сделал тестовые модули в одном из которых всего один интерфейс и класс его _реализующий_, а во втором никаких интерфейсов нет.

D_S>Просто из твоего постинга не совсем понятно — есть ли взаимосвязь между модулями на уровне метаданных.

В управляющем модуле есть Reference на первый модуль где собственно и описан интерфейс, который нужно получить от My_object
Re: Приведение типа
От: AlexZu Россия  
Дата: 16.12.03 13:37
Оценка: 3 (1)
Здравствуйте, Павел Киселев, Вы писали:


Скорее всего проблема в том, что здесь:
ПК>
LIB_TEST.ITest My_Test = (LIB_TEST.ITest)My_object;

загружается сборка (содержащая LIB_TEST.ITest) отличная от той которая загружается здесь:
ПК>
System.Reflection.Assembly CurrentAssembly = System.Reflection.Assembly.LoadFrom("C:\\LIB_TEST.dll");


Попросту говоря сборки находятся в разных местах в файловой системе, для проверки этого посмотрите свойство typeof(LIB_TEST.ITest).Assembly.Location и у CurrentAssembly.Location.
Re[3]: Приведение типа
От: mikа Stock#
Дата: 16.12.03 13:37
Оценка:
Здравствуйте, Павел Киселев, Вы писали:

А у тебя версия сборки статично прописана?
Re[3]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 16.12.03 13:39
Оценка:
1. уберите референс на модуль TEST_LIB.
2. перенесите интерфейс ITest в приложение.
3. попробуйте еще раз.
... << RSDN@Home 1.1.0 stable >>
Re[3]: Приведение типа
От: Dr_Sh0ck Беларусь  
Дата: 16.12.03 13:41
Оценка:
Здравствуйте, Павел Киселев, Вы писали:

D_S>>ИМХО тут надо было делать не так. Лучше проверять наличие интерфейса не по текстовуму имени, а по типу.


ПК>Да дело то в том, что

ПК>
ПК>My_object = System.Activator.CreateInstance(CurType);
ПК>

ПК>выполняется без проблем, т.е. конструктор данного класа вызывается

Ну и что?! какого такого "данного". Ты просто перебираешь типы в сборке и для некоего типа, который реализует интерфейст с именем LIB_TEST.ITest, создаешь его экземпляр. Что тут такого?
Do not fake yourself ;)
ICQ#: 198114726
Re[3]: Приведение типа
От: Dr_Sh0ck Беларусь  
Дата: 16.12.03 13:42
Оценка:
Здравствуйте, Павел Киселев, Вы писали:

ПК>Специально сделал тестовые модули в одном из которых всего один интерфейс и класс его _реализующий_, а во втором никаких интерфейсов нет.


ПК>В управляющем модуле есть Reference на первый модуль где собственно и описан интерфейс, который нужно получить от My_object


Ну тогда внешне, вроде, все прилично
Do not fake yourself ;)
ICQ#: 198114726
Re[3]: Приведение типа
От: Dr_Sh0ck Беларусь  
Дата: 16.12.03 13:45
Оценка:
Здравствуйте, Павел Киселев, Вы писали:

ПК>Специально сделал тестовые модули в одном из которых всего один интерфейс и класс его _реализующий_, а во втором никаких интерфейсов нет.


И все же попробуй вместо поиска интерфейса по текстовому имени делать поиск по typeof
И еще попробуй заменить LoadFrom на что-нибудь другое аналогичное
Do not fake yourself ;)
ICQ#: 198114726
Re[4]: Приведение типа
От: mikа Stock#
Дата: 16.12.03 13:50
Оценка: 1 (1)
Здравствуйте, Dr_Sh0ck, Вы писали:

D_S>Здравствуйте, Павел Киселев, Вы писали:


ПК>>Специально сделал тестовые модули в одном из которых всего один интерфейс и класс его _реализующий_, а во втором никаких интерфейсов нет.


D_S>И все же попробуй вместо поиска интерфейса по текстовому имени делать поиск по typeof

D_S>И еще попробуй заменить LoadFrom на что-нибудь другое аналогичное

Лучше сделать так

Debug.Assert(typeof(IMyInterface).FullName == myObject.GetType().GetInterfaces()[0].FullName)
Re[4]: Приведение типа
От: Павел Киселев  
Дата: 16.12.03 14:01
Оценка:
Здравствуйте, mikа, Вы писали:

M>А у тебя версия сборки статично прописана?


Прописал статично, не помогает
Re[5]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 16.12.03 14:01
Оценка:
M>Лучше сделать так
M>Debug.Assert(typeof(IMyInterface).FullName == myObject.GetType().GetInterfaces()[0].FullName)
а чем это лучше? воспользоваться интерфейсом все равно не удастся. не через Invoke же вызывать методы.
... << RSDN@Home 1.1.0 stable >>
Re[6]: Приведение типа
От: Dr_Sh0ck Беларусь  
Дата: 16.12.03 14:05
Оценка:
Здравствуйте, Алексей Одинцов, Вы писали:

M>>Лучше сделать так

M>>Debug.Assert(typeof(IMyInterface).FullName == myObject.GetType().GetInterfaces()[0].FullName)
АО>а чем это лучше? воспользоваться интерфейсом все равно не удастся. не через Invoke же вызывать методы.

Это поможет разобраться где у тебя глюк в программе
Do not fake yourself ;)
ICQ#: 198114726
Re[6]: Приведение типа
От: mikа Stock#
Дата: 16.12.03 14:05
Оценка: 3 (1)
Здравствуйте, Алексей Одинцов, Вы писали:

M>>Лучше сделать так

M>>Debug.Assert(typeof(IMyInterface).FullName == myObject.GetType().GetInterfaces()[0].FullName)
АО>а чем это лучше? воспользоваться интерфейсом все равно не удастся. не через Invoke же вызывать методы.

Это код для проверки. Так быстрее локализовать проблемы. Если исключение на строчке будет, то

myObject.GetType().Assembly.Name
myObject.GetType().Assembly.Location
typeof(IMyInterface).Assembly.Name
typeof(IMyInterface).Assembly.Location
Re[7]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 16.12.03 14:14
Оценка:
Здравствуйте, mikа, Вы писали:
имхо, и так ясно, что у него не совпадают типы. и чтобы пользоваться ранним связыванием, ему надо использовать интерфейс определенный на этапе компиляции, а не загруженный неизвестно когда.

а с тем что из ассембли ему по-любому придется динамически работать.
... << RSDN@Home 1.1.0 stable >>
Re[8]: Приведение типа
От: mikа Stock#
Дата: 16.12.03 14:20
Оценка:
Здравствуйте, Алексей Одинцов, Вы писали:

АО>Здравствуйте, mikа, Вы писали:

АО>имхо, и так ясно, что у него не совпадают типы.

Почему же Я могу привести кучу примеров почему этот код может выдавать ошибку при одинаковых интерфейсах.

АО>и чтобы пользоваться ранним связыванием, ему надо использовать интерфейс определенный на этапе компиляции, а не загруженный неизвестно когда.


К чему ты это вообще сказал?

АО>а с тем что из ассембли ему по-любому придется динамически работать.


?? Я написал код для того, чтобы проверить ралидность Если не работает, значит нужно посмотректь что откуда берется (это тоже написал) Какие поздние связывание? К чему ты это вообще?
Re[4]: Приведение типа
От: Павел Киселев  
Дата: 16.12.03 14:32
Оценка:
Здравствуйте, Алексей Одинцов, Вы писали:

АО>1. уберите референс на модуль TEST_LIB.

АО>2. перенесите интерфейс ITest в приложение.
АО>3. попробуйте еще раз.

Перенес, получил ExecutingAssembly, далее по коду все как и было.
Все получилось, но почему тогда не работает так как написано у меня?
Re[9]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 16.12.03 14:34
Оценка:
Здравствуйте, mikа, Вы писали:
M>?? Я написал код для того, чтобы проверить ралидность Если не работает, значит нужно посмотректь что откуда берется (это тоже написал) Какие поздние связывание? К чему ты это вообще?
к тому что он пишет

LIB_TEST.ITest My_Test = (LIB_TEST.ITest)My_object;
My_Test.Init();

этот код не скомпилится, если нет информации об интерфейсе LIB_TEST.ITest. Если в загруженном модуле интерфейс другой — не произойдет и (LIB_TEST.ITest)My_object, если класс не реализует именно этот интерфейс.

а если он загрузил библиотеку с каким-то там интерфейсом, как бы он там не назывался, ему придется вызывать методы этого интерфейса через рефлекшн, если этот интерфейс не ассоциирован с имеющимися.
... << RSDN@Home 1.1.0 stable >>
Re[5]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 16.12.03 14:54
Оценка:
Здравствуйте, Павел Киселев, Вы писали:
ПК>Перенес, получил ExecutingAssembly, далее по коду все как и было.
ПК>Все получилось, но почему тогда не работает так как написано у меня?
а это надо mika спросить. он походу шарит.
имхо просто потому что из разных ассемблей взято. но видимо можно как-то и срастить.
... << RSDN@Home 1.1.0 stable >>
Re[5]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 16.12.03 15:59
Оценка:
Здравствуйте, Павел Киселев, Вы писали:
ПК>Перенес, получил ExecutingAssembly, далее по коду все как и было.
ПК>Все получилось, но почему тогда не работает так как написано у меня?
при сравнении типов Type.Equals( Type t2 )
судя по IL (если не напутал) идет сравнение по ссылкам
src.UnderlyingSystemType и t2.UnderlyingSystemType
и похоже если их (ассемблей) 2, то типы эти возвращают разные ссылки как это разрулить я
... << RSDN@Home 1.1.0 stable >>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.