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: Приведение типа
От: 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[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[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[9]: Приведение типа
От: mikа Stock#
Дата: 17.12.03 12:52
Оценка: 1 (1)
Здравствуйте, Алексей Одинцов, Вы писали:

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


M>>Здравствуйте, Алексей Одинцов, Вы писали:

M>>Зааплодь проект. Вообще стожно даже в выводе результаов разобраться

АО>так? здесь


Ага. Посмотрел, потестировал, пришел к такому выводу

http://longhorn.msdn.microsoft.com/lhsdk/ref/ns/system.reflection/c/assembly/m/loadfile0.aspx

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.
Re[5]: Приведение типа
От: mikа Stock#
Дата: 16.12.03 19:23
Оценка: -1
Здравствуйте, Павел Киселев, Вы писали:

ПК>Здравствуйте, Алексей Одинцов, Вы писали:


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

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

ПК>Перенес, получил ExecutingAssembly, далее по коду все как и было.

ПК>Все получилось, но почему тогда не работает так как написано у меня?

Какой у вас конечный результат получился? Можешь еще раз привести листинг кода с указанием сборок.

Это раз. А два это то, что если сборки находятся в разных местах, и ты уже подгрузил одну сборку, то вторая просто не загрузится. Так что у тебя учавствовала только одна сборка (или, несколько, если были разные версии).
Re[8]: Приведение типа
От: AlexZu Россия  
Дата: 17.12.03 10:36
Оценка: -1
Здравствуйте, mikа, Вы писали:

M>Если ты думаешь, что между Assembly.LoadFrom и Assembly.Load есть разница в политике функционирования сборок в Нете,

Есть разница в политике загрузки сборок, и где-то на форуме было обсуждение этого. Да это и эскпериментально легко проверить, попробуй

M>то посмотри ниже

M>
M>public static Assembly LoadFrom(string assemblyFile, Evidence securityEvidence, byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
M>   {
M>      if (assemblyFile == null)
M>      {
M>        throw new ArgumentNullException("assemblyFile");
M>      }
M>      AssemblyName assemblyName = new AssemblyName();
M>      assemblyName.CodeBase = assemblyFile;
M>      assemblyName.SetHashControl(hashValue, hashAlgorithm);
M>      StackCrawlMark stackCrawlMark = StackCrawlMark.LookForMyCaller;
M>      return InternalLoad(assemblyName, false, securityEvidence, ref stackCrawlMark);
M>    }

M>    public static Assembly Load(string assemblyString)
M>    {
M>      StackCrawlMark stackCrawlMark = StackCrawlMark.LookForMyCaller;
M>      return InternalLoad(assemblyString, null, ref stackCrawlMark);
M>    }
M>


Что можно увидеть по этому коду? Что используются перегруженные версии InternalLoad?
Давай уж смотреть дальше:
Assembly.cs: Assembly.InternalLoad
AssemblyNative.cpp: AssemblyNative::Load
Re[10]: Приведение типа
От: AlexZu Россия  
Дата: 17.12.03 11:16
Оценка: :)
Здравствуйте, mikа, Вы писали:

M>А ты случаем не путаешь с LoadFile?

Нет, не путаю... Ты сам-то проверь, зачем спорить не убедившись что так оно и происходит?
Похожая ситуация здесь
Автор: avpavlov
Дата: 28.01.03
.
Приведение типа
От: Павел Киселев  
Дата: 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[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[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]: Приведение типа
От: Павел Киселев  
Дата: 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[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 >>
Re[6]: Приведение типа
От: Dr_Sh0ck Беларусь  
Дата: 17.12.03 06:26
Оценка:
Здравствуйте, Алексей Одинцов, Вы писали:

АО>и похоже если их (ассемблей) 2, то типы эти возвращают разные ссылки как это разрулить я


Если тип один и тот же, то и ссылка будет одной и той же.
Do not fake yourself ;)
ICQ#: 198114726
Re[6]: Приведение типа
От: AlexZu Россия  
Дата: 17.12.03 09:34
Оценка:
Здравствуйте, mikа, Вы писали:

M>Это раз. А два это то, что если сборки находятся в разных местах, и ты уже подгрузил одну сборку, то вторая просто не загрузится.

Еще как загрузится, если использовать Assembly.LoadFrom.
Re[7]: Приведение типа
От: mikа Stock#
Дата: 17.12.03 10:13
Оценка:
Здравствуйте, AlexZu, Вы писали:

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


M>>Это раз. А два это то, что если сборки находятся в разных местах, и ты уже подгрузил одну сборку, то вторая просто не загрузится.

AZ>Еще как загрузится, если использовать Assembly.LoadFrom.

Если ты думаешь, что между Assembly.LoadFrom и Assembly.Load есть разница в политике функционирования сборок в Нете, то посмотри ниже

public static Assembly LoadFrom(string assemblyFile, Evidence securityEvidence, byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
   {
      if (assemblyFile == null)
      {
        throw new ArgumentNullException("assemblyFile");
      }
      AssemblyName assemblyName = new AssemblyName();
      assemblyName.CodeBase = assemblyFile;
      assemblyName.SetHashControl(hashValue, hashAlgorithm);
      StackCrawlMark stackCrawlMark = StackCrawlMark.LookForMyCaller;
      return InternalLoad(assemblyName, false, securityEvidence, ref stackCrawlMark);
    }

    public static Assembly Load(string assemblyString)
    {
      StackCrawlMark stackCrawlMark = StackCrawlMark.LookForMyCaller;
      return InternalLoad(assemblyString, null, ref stackCrawlMark);
    }
Re[9]: Приведение типа
От: mikа Stock#
Дата: 17.12.03 10:56
Оценка:
Здравствуйте, AlexZu, Вы писали:

А ты случаем не путаешь с LoadFile?
Re[7]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 17.12.03 11:22
Оценка:
Здравствуйте, Dr_Sh0ck, Вы писали:
D_S>Если тип один и тот же, то и ссылка будет одной и той же.
а вот это как раз не так. по крайней мере если сделать еще раз LoadFrom даже на тот же файл, который уже загружен.
... << RSDN@Home 1.1.0 stable >>
Re[6]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 17.12.03 11:30
Оценка:
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 );
        }
    }
}


получается:
True and False
interface SameName.I2, TestLib, Version=1.0.1446.31382, Culture=neutral, PublicK
eyToken=null:
interface SameName.I1, BaseLib, Version=1.0.1446.31382, Culture=neutral, PublicK
eyToken=null:
SameName.I2, TestLib, Version=1.0.1446.31382, Culture=neutral, PublicKeyToken=nu
ll
False
True
False
SameName.I2, TestLib, Version=1.0.1446.31382, Culture=neutral, PublicKeyToken=nu
ll


при этом 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 не распознается как тот же тип.
... << RSDN@Home 1.1.0 stable >>
Re[7]: Приведение типа
От: mikа Stock#
Дата: 17.12.03 12:12
Оценка:
Здравствуйте, Алексей Одинцов, Вы писали:

Зааплодь проект. Вообще стожно даже в выводе результаов разобраться
Re[8]: Приведение типа
От: Алексей Одинцов Россия  
Дата: 17.12.03 12:15
Оценка:
Здравствуйте, mikа, Вы писали:

M>Здравствуйте, Алексей Одинцов, Вы писали:

M>Зааплодь проект. Вообще стожно даже в выводе результаов разобраться

так? здесь
... << RSDN@Home 1.1.0 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.