Подтвердить что ты не робот

.NET: Невозможно использовать объект для взаимодействия с ним.

У меня есть класс (TabControlH60), который наследуется от базового класса (UserControl) и реализует интерфейс (IFrameworkClient). Я создаю экземпляр объекта с помощью класса .NET Activator. С возвращенным экземпляром я могу применить к базовому классу UserControl, но не к интерфейсу. Исключение, которое я получаю, находится ниже кода snipet. Как мне перейти на интерфейс?

object obj = Activator.CreateInstance(objType);
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient

m_Client = (UserControl)obj;                 // base class cast works
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails

// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window.
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type 
    'FPG.AFF.Interfaces.IFrameworkClient'."}
4b9b3361

Ответ 1

У меня те же проблемы с моей библиотекой, обеспечивающей "плагиновую" функциональность... Я наконец-то ее обработал...

Вот моя проблема: у меня была одна основная сборка с использованием плагинов, одна сборка с плагином (Plugin.dll) И (важная) другая сборка, обеспечивающая плагин-функциональность (Library.dll).

Плагин .dll ссылается на основную сборку (для ее расширения) и Library.dll с помощью функции plugin-func. - его двоичные файлы попали в каталог "./Plugins" относительно основной сборки.

В основной сборке также упоминается функция plugin-func. сборка для использования "PluginManager" написана. Этот "PluginManager" получает путь и загружает все файлы *.dll через отражение, чтобы проанализировать, есть ли "IPlugin" -интерфейс (который также поступает из Library.dll).

Каждый раз, когда я вызывал PluginManager для загрузки плагинов, он не мог отнести их к "IPlugin" , хотя они реализовали его.

Я чуть не рассердился, но потом выяснил всю проблему. При компиляции плагина в директорию "./Plugins" была записана не только "Plugin.dll", но и "Library.dll" . Случайно загружая "Library.dll" каждый раз с помощью моего модуля PluginManager, я теперь имел два типа "IPlugin" - один в фактической "Library.dll" , который используется из основной сборки и тот, который был загружен через мой PluginManager - и они были несовместимы!

Внимание - если вы просто не загружаете "./Plugins/Library.dll", вы все же сталкиваетесь с проблемой - потому что если вы загружаете "Plugin.dll", который ссылается на "Library.dll" , то он просто использует тот, который находится в тот же каталог... TILT...!! Мой PluginManager теперь просто удаляет "Library.dll" , где он его находит.

Подсказка: убедитесь, что вы не имеете доступа к двум сборкам в разных контекстах!

Ответ 2

Наиболее вероятная причина здесь в том, что IFrameworkClient является из другой сборки в двух случаях и, следовательно, является другим типом .NET. Даже если это тот же код, он может быть другого типа.

Проверьте AssemblyQualifiedName. Также обратите внимание, что если вы загружаете эту сборку с отражением, вы можете получить другой тип даже с тем же AssemblyQualifiedName, благодаря контексту load.

Ответ 3

Определите интерфейс IFrameworkClient в независимом пространстве имен (должно быть в пространстве имен) независимого проекта (библиотеки классов). Затем добавьте refrence библиотеки классов для управления проектом и основным проектом

Ответ 4

Что-то подсказывает, что ваш образец кода оставляет некоторые вещи...

class Program
{
    static void Main(string[] args)
    {
        var type = typeof(MyClass);
        object obj = Activator.CreateInstance(type);
        Type[] interfaces = obj.GetType().GetInterfaces();

        var m_Client = (UserControl)obj;          
        IFrameworkClient fc = (IFrameworkClient)obj;
    }
}

public interface IFrameworkClient { }

public class UserControl { }

public class MyClass : UserControl, IFrameworkClient { }

Это компилируется и выполняется.

Я уверен, что DLL, содержащая определение IFrameworkClient, еще не загружена до того, как вы попытаетесь выполнить бросок. Это может произойти, если вы используете Activator.CreateInstance.

Попробуйте вставить var forceLoad = typeof(IFrameworkClient); перед трансляцией.

Ответ 5

Когда Interface в другой сборке и я получаю мой класс динамически в run-time в другой сборке, interface casting будет сбой, как ваш sample (С# знает наш интерфейс как другой тип, чем тот, который унаследовал от этого класса).

Это мой простой и полезный метод в следующих случаях:

Когда я уверен, что мой Class унаследовал от упомянутого Interface (eq. IFrameworkClient), поэтому я пишу одну магическую строку кода следующим образом:

dynamic fc = obj as IFrameworkClient ?? (dynamic) obj;

С помощью этой техники вы можете:

  • Введите коды после этой строки кода для fc в design time на основе Interface members информации и системы управления версиями.
  • Предотвратить любую ошибку литья интерфейса при run-time

Примечания:

  • Вам нужно C# v4 использовать dynamic type
  • Обычно я не люблю использовать типы dynamic в моих кодах, но в некоторых случаях это может нам помочь.

Ответ 6

Используйте оператор as:)

...
m_Client = obj as IFrameworkClient;
if (m_Client != null)  //Remember to check for null in case the cast fails
   ...
...

Ответ 7

Если класс FPG.H60.AFF.TabControlH60 действительно реализует IFrameworkClient, не должно быть причин, по которым это не получится. Единственное, что я могу придумать, вызывает это исключение, если сборка, содержащая IFrameworkClient, сильно пронумерована, и объект Tab Control ссылается на другую версию содержащей сборки, или вы используете другой интерфейс с именем IFrameworkClient.

Ответ 8

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

Причина, по которой я использовал события сборки в этом случае (вместо добавления DLL в качестве ссылки), заключается в том, что архитектура такова, что основное приложение должно ссылаться только на типы интерфейса, а все остальное должно загружаться динамически.

TL;DR; В случае загрузки типов динамически из другой DLL, убедитесь, что вы скопируете самую последнюю версию этой DLL в каталог bin, используя события сборки, иначе кастинг может не работать, когда кажется, что он должен.

Ответ 9

Я столкнулся с той же проблемой, и я просто добавил следующий код

private void LoadAssemblyPlugins(string dll)

    Assembly ass = AppDomain.CurrentDomain.GetAssemblies()
        .FirstOrDefault(a => new Uri(a.CodeBase).Equals(new Uri(dll)));

   if (ass == null)
       // Load it here
       // use activator here

Хотя в производстве это никогда не будет проблемой, в модульном тесте это было, но теперь мне не нужно загружать его снова и создавать "другой тип"

Ответ 10

Приведение не работает, потому что вы пытаетесь использовать тип object для интерфейса. Если вы замените линию литья интерфейса:

IFrameworkClient fc = (IFrameworkClient)m_Client;

Он будет работать.

В качестве альтернативы, я мягко уверен, что вы можете сделать трансляцию из объекта в интерфейс с помощью оператора as.

См. эту статью для получения дополнительной информации: http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

Еще один кусочек головоломки. Интерфейсы не связаны с object: http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx