.Net Загрузка обобщений с использованием Reflection, затем Casting - PullRequest
0 голосов
/ 22 февраля 2011

Это продолжение этого вопроса . Только читайте, если вы заинтересованы в предыстории.

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

У меня есть вторая сборка, на которую ссылается и мой текущий проект, и сборка, которую я загружаю, которая содержит интерфейсы:

  • IJob
  • IJobWrapper(Of IJob)

Сборка, которую я загружаю (назовите ее Jobs.dll), содержит JobWrapper(Of IJob) - реализующий интерфейс IJobWrapper.

Jobs.dll также содержит несколько заданий, которые реализуют IJob

Теперь я загружаю соответствующие типы в контейнер (Unity) и вытаскиваю их по мере необходимости. Это работает (то есть контейнер разрешает ссылки соответствующим образом и создает объект)

Примечание: JobType и JobWrapperType ниже извлекаются с помощью отражения.

В частности:

        Dim TypeArgs As Type() = {JobType}
        Dim WrappedJob = JobWrapperType.MakeGenericType(TypeArgs)
        Dim ContainerJob = Container.Resolve(WrappedJob)
        Dim JobInstance = DirectCast(ContainerJob, IJobWrapper(Of IJob))

Здесь выдается ошибка - последняя строка с приведением.

ContainerJob в строке 3 технически является объектом, так как мне нужно использовать перегрузку, не являющуюся универсальной, для разрешения (т. Е. Параметр Type не является '(Of XXX)').

Согласно отладчику, на самом деле это MyProject.Jobs.JobWrapper(Of MyProject.Jobs.DailyStatusReport)

MyProject.Jobs.JobWrapper Инвентарь IJobWrapper(Of IJob) MyProject.Jobs.DailyStatusReport Инвентарь IJob

DirectCast выдает это исключение:

Unable to cast object of type 'MyProject.Jobs.JobWrapper`1[MyProject.Jobs.DailyStatusReport]' to type 'MyProject.JobService.Common.IJobWrapper`1[MyProject.JobService.Common.IJob]'.

Может кто-нибудь объяснить, почему он не может выполнять бросок / как его обойти? Мне интересно, если у него возникли проблемы с сопоставлением интерфейса, определенного в сборке, на которую ссылаются, изнутри Jobs.dll - Но если это так, я не уверен, как их согласовать.

Большое спасибо.

РЕДАКТИРОВАТЬ:

Примеры методов из интерфейсов:

IJob:

Function ShouldExectute() As Boolean
Sub Execute()

IJobWrapper:

Function ShouldExectute() As Boolean
Sub Execute()
ReadOnly Property DatabaseId as Long
ReadOnly Property Name as String
ReadOnly Property IsDisabled As Boolean

Например, Job Wrapper никогда не возвращает ничего с типом IJob. Он использует информацию о типе для поиска различных атрибутов, которые были присоединены к классу, который реализует IJob, и считывает информацию.

1 Ответ

2 голосов
/ 22 февраля 2011

Невозможно выполнить это приведение (с отражением или без него), поскольку параметры универсального типа должны точно соответствовать. Таким образом, вы можете разыграть AnyImplementationOfIJobWrapper(Of IJob) до IJobWrapper(Of IJob), но вы не можете разыграть AnyImplementationOfIJobWrapper(Of AnyImplementationOfIJob) до IJobWrapper(Of IJob).

Однако, если вы управляете кодом для IJobWrapper, вы можете превратить его в ковариантный интерфейс , объявив его как Interface IJobWrapper(Of Out IJob). Это позволит вам выполнить приведение. Это тот же механизм, который позволяет вам, например, присвойте IEnumerable(Of Subclass) IEnumerable(Of Superclass).

(Не стесняйтесь исправлять любые синтаксические ошибки, которые я мог допустить; давно я не использовал VB.)

Естественным вопросом было бы «Почему этот бросок не разрешен в первую очередь?» Причина в том, что это может привести к опасным ситуациям: предположим, что у вас есть IList(Of Vehicle) vehicles. Кажется естественным, что можно назначить List(Of Car) на vehicles, поскольку список автомобилей можно рассматривать как список транспортных средств. Но если мы разрешим vehicles ссылаться на то, что действительно является List(Of Car), мы можем попытаться добавить Boat к vehicles, что должно быть разрешено, поскольку vehicles представляется списком Vehicle s. а Boat - это Vehicle. Однако фактический список ограничен только 1030 * с, поэтому мы должны либо сгенерировать исключение (очень неожиданно для пользователя vehicles), либо вставить Boat в список Car с (создание катастрофа в ожидании). Решение: запретить актерский состав. IEnumerable (но не IList) можно сделать ковариантным, поскольку он содержит только методы, позволяющие читать из коллекции. Следовательно, IEnumerable(Of Car) можно назначить IEnumerable(Of Vehicle), поскольку IEnumerable позволяет только читать содержимое коллекции, но не вставлять в нее новые объекты.

...