ПК>Но почему-то при приведении типа от object возникает исключение System.InvalidCastException - "Specified cast is not valid."
ИМХО тут надо было делать не так. Лучше проверять наличие интерфейса не по текстовуму имени, а по типу. А причина может быть в том, что ты просто объявил два разных интрефейса с одним и тем же именем — ITest в двух этих модулях?
Просто из твоего постинга не совсем понятно — есть ли взаимосвязь между модулями на уровне метаданных.
Попросту говоря сборки находятся в разных местах в файловой системе, для проверки этого посмотрите свойство typeof(LIB_TEST.ITest).Assembly.Location и у CurrentAssembly.Location.
Здравствуйте, Алексей Одинцов, Вы писали:
M>>Лучше сделать так M>>Debug.Assert(typeof(IMyInterface).FullName == myObject.GetType().GetInterfaces()[0].FullName) АО>а чем это лучше? воспользоваться интерфейсом все равно не удастся. не через Invoke же вызывать методы.
Это код для проверки. Так быстрее локализовать проблемы. Если исключение на строчке будет, то
Здравствуйте, Dr_Sh0ck, Вы писали:
D_S>Здравствуйте, Павел Киселев, Вы писали:
ПК>>Специально сделал тестовые модули в одном из которых всего один интерфейс и класс его _реализующий_, а во втором никаких интерфейсов нет.
D_S>И все же попробуй вместо поиска интерфейса по текстовому имени делать поиск по typeof D_S>И еще попробуй заменить LoadFrom на что-нибудь другое аналогичное
Здравствуйте, Алексей Одинцов, Вы писали:
АО>Здравствуйте, mikа, Вы писали:
M>>Здравствуйте, Алексей Одинцов, Вы писали: M>>Зааплодь проект. Вообще стожно даже в выводе результаов разобраться
АО>так? здесь
Ага. Посмотрел, потестировал, пришел к такому выводу
LoadFrom cannot be used to load assemblies that have the same identities but different paths; it will load only the first such assembly.
написано не совсем верно. Если сборка загружается динамически (на нее нет ссылки), то ее можно загрузить только в единственном экземпляре. Если же на нее уже была повешена ссылка во время компиляции, то можно загрузить еще один экземпляр этой сборки. При этом, физически она будет отличаться. Отсюда и разные типы.
Вывод. Можно только гадать, чем в нутри отличаються методы Assembly.nLoad и Assembly.nLoadFile. Ведь фактически подгрузка второй динамической сборки (Assembly.LoadFrom) есть вызов Assembly.LoadFile.
Здравствуйте, Павел Киселев, Вы писали:
ПК>Здравствуйте, Алексей Одинцов, Вы писали:
АО>>1. уберите референс на модуль TEST_LIB. АО>>2. перенесите интерфейс ITest в приложение. АО>>3. попробуйте еще раз.
ПК>Перенес, получил ExecutingAssembly, далее по коду все как и было. ПК>Все получилось, но почему тогда не работает так как написано у меня?
Какой у вас конечный результат получился? Можешь еще раз привести листинг кода с указанием сборок.
Это раз. А два это то, что если сборки находятся в разных местах, и ты уже подгрузил одну сборку, то вторая просто не загрузится. Так что у тебя учавствовала только одна сборка (или, несколько, если были разные версии).
Здравствуйте, mikа, Вы писали:
M>Если ты думаешь, что между Assembly.LoadFrom и Assembly.Load есть разница в политике функционирования сборок в Нете,
Есть разница в политике загрузки сборок, и где-то на форуме было обсуждение этого. Да это и эскпериментально легко проверить, попробуй
M>то посмотри ниже M>
Что можно увидеть по этому коду? Что используются перегруженные версии InternalLoad?
Давай уж смотреть дальше:
Assembly.cs: Assembly.InternalLoad
AssemblyNative.cpp: AssemblyNative::Load
Здравствуйте, mikа, Вы писали:
M>А ты случаем не путаешь с LoadFile?
Нет, не путаю... Ты сам-то проверь, зачем спорить не убедившись что так оно и происходит?
Похожая ситуация здесь
выполняется без проблем, т.е. конструктор данного класа вызывается
D_S>А причина может быть в том, что ты просто объявил два разных интрефейса с одним и тем же именем — ITest в двух этих модулях?
Специально сделал тестовые модули в одном из которых всего один интерфейс и класс его _реализующий_, а во втором никаких интерфейсов нет.
D_S>Просто из твоего постинга не совсем понятно — есть ли взаимосвязь между модулями на уровне метаданных.
В управляющем модуле есть Reference на первый модуль где собственно и описан интерфейс, который нужно получить от My_object
Здравствуйте, Павел Киселев, Вы писали:
D_S>>ИМХО тут надо было делать не так. Лучше проверять наличие интерфейса не по текстовуму имени, а по типу.
ПК>Да дело то в том, что ПК>
ПК>выполняется без проблем, т.е. конструктор данного класа вызывается
Ну и что?! какого такого "данного". Ты просто перебираешь типы в сборке и для некоего типа, который реализует интерфейст с именем LIB_TEST.ITest, создаешь его экземпляр. Что тут такого?
Здравствуйте, Павел Киселев, Вы писали:
ПК>Специально сделал тестовые модули в одном из которых всего один интерфейс и класс его _реализующий_, а во втором никаких интерфейсов нет.
ПК>В управляющем модуле есть Reference на первый модуль где собственно и описан интерфейс, который нужно получить от My_object
Здравствуйте, Павел Киселев, Вы писали:
ПК>Специально сделал тестовые модули в одном из которых всего один интерфейс и класс его _реализующий_, а во втором никаких интерфейсов нет.
И все же попробуй вместо поиска интерфейса по текстовому имени делать поиск по typeof
И еще попробуй заменить LoadFrom на что-нибудь другое аналогичное
M>Лучше сделать так M>Debug.Assert(typeof(IMyInterface).FullName == myObject.GetType().GetInterfaces()[0].FullName)
а чем это лучше? воспользоваться интерфейсом все равно не удастся. не через Invoke же вызывать методы.
Здравствуйте, Алексей Одинцов, Вы писали:
M>>Лучше сделать так M>>Debug.Assert(typeof(IMyInterface).FullName == myObject.GetType().GetInterfaces()[0].FullName) АО>а чем это лучше? воспользоваться интерфейсом все равно не удастся. не через Invoke же вызывать методы.
Это поможет разобраться где у тебя глюк в программе
Здравствуйте, mikа, Вы писали:
имхо, и так ясно, что у него не совпадают типы. и чтобы пользоваться ранним связыванием, ему надо использовать интерфейс определенный на этапе компиляции, а не загруженный неизвестно когда.
а с тем что из ассембли ему по-любому придется динамически работать.
Здравствуйте, Алексей Одинцов, Вы писали:
АО>Здравствуйте, mikа, Вы писали: АО>имхо, и так ясно, что у него не совпадают типы.
Почему же Я могу привести кучу примеров почему этот код может выдавать ошибку при одинаковых интерфейсах.
АО>и чтобы пользоваться ранним связыванием, ему надо использовать интерфейс определенный на этапе компиляции, а не загруженный неизвестно когда.
К чему ты это вообще сказал?
АО>а с тем что из ассембли ему по-любому придется динамически работать.
?? Я написал код для того, чтобы проверить ралидность Если не работает, значит нужно посмотректь что откуда берется (это тоже написал) Какие поздние связывание? К чему ты это вообще?
Здравствуйте, Алексей Одинцов, Вы писали:
АО>1. уберите референс на модуль TEST_LIB. АО>2. перенесите интерфейс ITest в приложение. АО>3. попробуйте еще раз.
Перенес, получил ExecutingAssembly, далее по коду все как и было.
Все получилось, но почему тогда не работает так как написано у меня?
Здравствуйте, mikа, Вы писали: M>?? Я написал код для того, чтобы проверить ралидность Если не работает, значит нужно посмотректь что откуда берется (это тоже написал) Какие поздние связывание? К чему ты это вообще?
к тому что он пишет
этот код не скомпилится, если нет информации об интерфейсе LIB_TEST.ITest. Если в загруженном модуле интерфейс другой — не произойдет и (LIB_TEST.ITest)My_object, если класс не реализует именно этот интерфейс.
а если он загрузил библиотеку с каким-то там интерфейсом, как бы он там не назывался, ему придется вызывать методы этого интерфейса через рефлекшн, если этот интерфейс не ассоциирован с имеющимися.
Здравствуйте, Павел Киселев, Вы писали: ПК>Перенес, получил ExecutingAssembly, далее по коду все как и было. ПК>Все получилось, но почему тогда не работает так как написано у меня?
а это надо mika спросить. он походу шарит.
имхо просто потому что из разных ассемблей взято. но видимо можно как-то и срастить.
Здравствуйте, Павел Киселев, Вы писали: ПК>Перенес, получил ExecutingAssembly, далее по коду все как и было. ПК>Все получилось, но почему тогда не работает так как написано у меня?
при сравнении типов Type.Equals( Type t2 )
судя по IL (если не напутал) идет сравнение по ссылкам
src.UnderlyingSystemType и t2.UnderlyingSystemType
и похоже если их (ассемблей) 2, то типы эти возвращают разные ссылки как это разрулить я
Здравствуйте, mikа, Вы писали:
M>Это раз. А два это то, что если сборки находятся в разных местах, и ты уже подгрузил одну сборку, то вторая просто не загрузится.
Еще как загрузится, если использовать Assembly.LoadFrom.
Здравствуйте, AlexZu, Вы писали:
AZ>Здравствуйте, mikа, Вы писали:
M>>Это раз. А два это то, что если сборки находятся в разных местах, и ты уже подгрузил одну сборку, то вторая просто не загрузится. AZ>Еще как загрузится, если использовать Assembly.LoadFrom.
Если ты думаешь, что между Assembly.LoadFrom и Assembly.Load есть разница в политике функционирования сборок в Нете, то посмотри ниже
Здравствуйте, Dr_Sh0ck, Вы писали: D_S>Если тип один и тот же, то и ссылка будет одной и той же.
а вот это как раз не так. по крайней мере если сделать еще раз LoadFrom даже на тот же файл, который уже загружен.
M>Это раз. А два это то, что если сборки находятся в разных местах, и ты уже подгрузил одну сборку, то вторая просто не загрузится. Так что у тебя учавствовала только одна сборка (или, несколько, если были разные версии).
using System;
namespace SameName
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
System.Reflection.Assembly a1 = System.Reflection.Assembly.LoadFrom("..\\..\\..\\TestLib\\bin\\Debug\\TestLib.dll");
Type t1 = a1.GetType("SameName.Class1");
object o1 = System.Activator.CreateInstance( t1 );
Console.WriteLine( "{0} and {1}", o1 is I1, o1 is I2 );
Type [] ifs = t1.GetInterfaces();
foreach( Type t in ifs )
{
Console.WriteLine( "interface {0}: ", t.AssemblyQualifiedName );
}
Console.WriteLine( typeof(I2).AssemblyQualifiedName );
Type ti2 = a1.GetType("SameName.I2");
Console.WriteLine( ti2 == typeof(I2) );
Console.WriteLine( ti2.AssemblyQualifiedName == typeof(I2).AssemblyQualifiedName );
Console.WriteLine( ti2.Assembly == typeof(I2).Assembly );
Console.WriteLine( ti2.UnderlyingSystemType.AssemblyQualifiedName );
}
}
}
при этом interface SameName.I1 объявлен в BaseLib.dll
интерфейс interface SameName.I2 объявлен в TestLib.dll
класс SameName.C1ass1 объявлен и в TestLib.dll (он и создается)
TestLib.dll ссылается на BaseLib.dll
TestExe.exe (текст которого приведен) ссылается на обе (TestLib.dll и BaseLib.dll)
тем не менее, как видно I2 не распознается как тот же тип.