InvalidCastException для двух объектов одного типа - PullRequest
20 голосов
/ 23 марта 2010

У меня странная проблема, с которой я не справлюсь сам. Класс в модели моего mvp-проекта, спроектированного как синглтон, вызывает InvalidCastException. Источник ошибки находится в этой строке кода, где десериализованный объект назначается переменной экземпляра класса: engineObject = (ENGINE)xSerializer.Deserialize(str); Это происходит всякий раз, когда я пытаюсь добавить один из моих элементов UserControls в форму или в другой UC. Все мои UC имеют специальный презентатор, который обращается к вышеупомянутой переменной экземпляра класса singleton. Вот что я получаю, когда пытаюсь добавить UC куда-нибудь:

'System.TypeInitializationException: инициализатор типа для' MVP.Model.EngineData 'вызвал исключение. ----> System.InvalidCastException: [A] Engine не может быть приведен к [B] Engine. Тип A происходит от 'MVP.Model, Version = 1.0.0.0, Culture = нейтральный, PublicKeyToken = null' в контексте 'LoadNeither' в местоположении '[...] \ AppData \ Roaming \ Microsoft \ VisualStudio \ 9.0 \ ProjectAssemblies \ uankw1hh01 \ MVP.Model.dll. Тип B происходит из 'MVP.Model, Version = 1.0.0.0, Culture = нейтральный, PublicKeyToken = null' в контексте 'LoadNeither' в местоположении '[...] \ AppData \ Roaming \ Microsoft \ VisualStudio \ 9.0 \ ProjectAssemblies \ u_hge2de01 \ MVP.Model.dll»...

Итак, у меня как-то есть две сборки, и к ним нет доступа из папки моего проекта, а из папки временных файлов VS? Я много гуглил и нашел только следующее: Исключение IronPython: [A] Персона не может быть приведена к [B] Персоне . Предлагается решение, но, во-первых, оно касается IronPhyton, а во-вторых, я не знаю, где его использовать в моем проекте?

Было бы замечательно, если бы вы могли помочь мне здесь :-) ТНХ

Ответы [ 4 ]

18 голосов
/ 23 марта 2010

Типы для каждой сборки; если «одна и та же» сборка загружена дважды, то типы в каждой «копии» сборки не считаются одинаковыми.

Эти проблемы обычно возникают, когда две сборки находятся в контекстах Load и LoadFrom. См

Разница между LoadFile и LoadFrom для сборок .NET?

и ссылку на блог suzcook для получения подробной информации по этому вопросу.

Кроме того, рассмотрите возможность использования средства просмотра журнала Fusion, чтобы помочь диагностировать проблему.

http://msdn.microsoft.com/en-us/library/e74a18c4%28VS.71%29.aspx

4 голосов
/ 19 августа 2017

Судя по контексту, в котором загружается сборка (контекст «LoadNeither»), некоторые разработчики могут делать что-то вроде загрузки сборки, которая была внутренне упакована как ресурс в ваше приложение. Если вы сделаете это, вы будете использовать обработчик событий AppDomain.CurrentDomain.AssemblyResolve, чтобы ваше приложение могло указать, где .NET должен получать любую конкретную сборку, которая ему нужна.

Мой ответ не объяснит махинации, как это сделать, - но я упоминаю об этом, потому что этот процесс привел непосредственно к той же самой ошибке, с которой столкнулся оригинальный постер. Как упоминает Эрик Липперт, типы создаются для каждой сборки. Поэтому, если вы загружаете отдельную сборку более одного раза, один и тот же определенный класс будет отображаться как разные классы - даже если визуальный осмотр показывает, что они кажутся одинаковыми.

Мы видели случаи, когда .NET вызывал ResolveEventHandler более одного раза для одной и той же DLL. Я не уверен, почему .NET иногда делает это (это произошло на некоторых машинах, но не на всех машинах). Но чтобы решить эту проблему, нам нужно было сохранить глобальный список дескрипторов для загруженных сборок, чтобы, если .NET захотел загрузить сборку снова, мы вернули дескриптор той же сборке, которая была первоначально загружена, вместо загрузки другой копии в память .

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

    public void AppStartup (object sender, StartupEventArgs e)
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    }

    public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
        dllName = dllName.Replace(".", "_");

        if (dllName.EndsWith("_resources")) return null;
        System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
        byte[] bytes = null;
        try
        {
            bytes = (byte[])rm.GetObject(dllName);
        }
        catch (Exception ex)
        {
        }
        if (bytes != null)
        {
            // the following call will return a newly loaded assembly
            //   every time it is called
            // if this function is called more than once for the same
            //   assembly, you'll load more than one copy into memory
            // this can cause the InvalidCastException
            // instead of doing this, you keep a global list of loaded
            //   assemblies, and return the previously loaded assembly
            //   handle, instead of loading it again
            return System.Reflection.Assembly.Load(bytes);
        }
        return null;
    }
3 голосов
/ 18 августа 2015

В моей ситуации были две копии одной и той же библиотеки DLL. Один находился в папке bin, а другой - в подпапке той же папки bin. Оба были загружены, удивительно, некоторые вещи работали нормально, но некоторые не работали, и именно тогда появилось это сообщение об ошибке:

System.InvalidOperationException; There was an error generating the XML document.; Source: System.Xml; TargetSite: Void Serialize(System.Xml.XmlWriter, System.Object, System.Xml.Serialization.XmlSerializerNamespaces, System.String, System.String);

В этом скрыто следующее внутреннее исключение (это было связано с Microsoft Dynamics CRM 4.0, но могло относиться к чему угодно)

System.InvalidCastException; [A]XXX.CRMCustomCode.YYY.CreateCompanyRequest cannot be cast to [B]XXX.CRMCustomCode.YYY.CreateCompanyRequest. Type A originates from 'XXX.CRMCustomCode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadFrom' at location 'C:\Program Files\Microsoft CRM\Server\bin\assembly\XXX.CRMCustomCode.dll'. Type B originates from 'XXX.CRMCustomCode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Program Files\Microsoft CRM\Server\bin\XXX.CRMCustomCode.dll'.; 

Я просто удалил дубликат dll (в C: \ Program Files \ Microsoft CRM \ Server \ bin), и ошибка исчезла.

2 голосов
/ 03 июня 2015

Мой конкретный случай - библиотека классов, указанная в веб-приложении, была переименована и перестроена. Старая версия библиотеки все еще находилась в папке bin под старым именем. Каркас загружает что угодно в папку bin (обе библиотеки) и выдает эту ошибку. Так происходит не только когда сборки загружаются явно. Очевидное решение в моем случае - очистить папку bin.

...