Передача объектов класса через разные версии сборки - PullRequest
3 голосов
/ 15 января 2012

Сценарий выглядит так -

  • У меня есть сборка, которая говорит «MyAssembly». В этой сборке определен интерфейс «IMyInterface».
  • В той же сборке у меня есть один класс (MyClass) с методом, определенным в нем как:

public void MyMethod (объект IMyInterface) {}

  • Теперь в моем проекте я создал интерфейс с тем же именем и точными свойствами, которые предоставляются интерфейсом «IMyInterface» в «MyAssembly».
  • У меня есть класс, который расширяет этот интерфейс (тот, который я создал в моем проекте), и я хочу передать объект этого класса в качестве параметра методу «MyMethod» в другой сборке, используя отражение.

Проблема -

  • Когда я пытаюсь вызвать метод с использованием отражения, я получаю следующее исключение: "Невозможно преобразовать объект в тип IMyInterface" .

Код -

Assembly myAssembly = Assembly.LoadFrom("MyAssembly");
object classObject = myAssembly.CreateInstance("MyClass");
Type classType = myAssembly.GetType("MyClass");
MethodInfo myMethod = classType.GetMethod("MyMethod", BindingFlags.Instance);

// Creating an object of class in the latest assembly and need to pass this
// to method in assembly with different version.
ClassExtendingMyInterface obj= new ClassExtendingMyInterface ();

myMethod.Invoke(classObject, new object[] { obj});

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

Другой подход, о котором я подумал, - создать в классе собственный динамический метод, который будет принимать объект моего класса.

Я пытался найти в Google и через Reflection.Emit или RunSharp , чтобы динамически создать свой собственный класс. Но мы можем использовать это только в наших динамически генерируемых сборках, но не можем создавать динамические методы или классы в уже существующих сборках.

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

Ответы [ 3 ]

6 голосов
/ 15 января 2012

Вы боретесь с тем, что называется «Идентификацией типа», очень важной контрмерой ада DLL в .NET Framework.Тип не просто идентифицируется по имени пространства имен и имени типа, он также включает атрибуты сборки, из которой он взят.В частности, отображаемое имя сборки, [AssemblyVersion], [AssemblyCulture], PublicKeyToken и (косвенно) ProcessorArchitecture.Вы можете увидеть «настоящее» имя типа с помощью свойства Type.AssemblyQualifiedName.Например, класс System.String - System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

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

Примечательно, что это требование несколько смягчено в .NET 4. Типы, которые были автоматически сгенерированы избиблиотека типов COM эквивалентна, если их имя и [Guid] совпадают.Это помогло устранить PIA и реализовать функцию «Вставить типы взаимодействия».Ничего, что относится к вашему делу.

1 голос
/ 15 января 2012

Если я правильно понимаю вашу проблему, я считаю, что вы хотите определить свои интерфейсы в их собственной сборке, а затем сослаться на общую сборку интерфейсов в каждой из двух других.Таким образом, каждая сборка ссылается на определение SAME Interface:

Создайте и соберите dll MyInterfaces:

namespace MyInterfaces
{
    public interface IMyInterface
    {
        void SharedMethod();
    }
}

Затем создайте свою первую сборку в другом проекте и установите ссылку наDLL создан для MyInterfaces.Создайте свой класс, отметив операторы using в верхней части модуля:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyInterfaces;

namespace MyFirstProject
{
    public class MyClass1
    {
        public void MyMethod(IMyInterface SomeObject) { }
    }
}

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

1 голос
/ 15 января 2012

Здесь:

Теперь в моем проекте я создал интерфейс с тем же именем и точными свойствами, которые предоставляются интерфейсом «IMyInterface» в «MyAssembly».

В этом проблема; недостаточно объявить одноименный интерфейс. Типы ограничены их сборкой; для CLR совершенно другой интерфейс.

Вместо этого добавьте ссылку к исходной сборке и реализуйте интерфейс, который уже определен. Он должен быть определен только один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...