使用反射然后铸造.NET泛型加载 [英] .Net Loading Generics using Reflection then Casting

查看:203
本文介绍了使用反射然后铸造.NET泛型加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个后续这个问题。只有不厌其烦地阅读它,如果你有兴趣的背景故事。

This is a follow-up to this question. Only bother reading it if you're interested in the back-story.

总之,我使用反射来加载一组通用的类型从一个程序集。该组件在运行时加载。

In short, I am using reflection to load a set of generic types from an assembly. The assembly is loaded at run time.

我有我的当前项目和组件引用的这两个我加载第二个组件,它包含的接口:

I have a second assembly referenced both by my current project and the assembly I'm loading which contains the interfaces:

  • IJob
  • IJobWrapper(中IJob)
  • IJob
  • IJobWrapper(Of IJob)

大会我加载(称之为 Jobs.dll )包含了一个 JobWrapper(中IJob) - 它实现了 IJobWrapper 接口。

The Assembly I'm loading (Call it Jobs.dll) contains a JobWrapper(Of IJob) - which implements the IJobWrapper interface.

Jobs.dll 还包含实现多个作业 IJob

Jobs.dll also contains multiple jobs which implement IJob

现在,我加载相应的类型到一个容器(统一),并在需要时将其拔出。这工作(即,容器解析引用适当的和实例化的对象)

Now, I'm loading the appropriate Types into a container (Unity) and pulling them out when required. This works (that is to say, the container resolves the references as appropriate and instantiates an object)

注: JobType JobWrapperType 以下是通过反射检索

NB: JobType and JobWrapperType below are retrieved via reflection.

具体做法是:

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

什么是扔在这里的错误是跟投的最后一行。

What's throwing an error here is the last line with the cast.

ContainerJob 在3号线在技术上是一个对象,因为我需要使用非泛型重载做分辨率(即一个类型参数不是一个(作者XXX) ')

ContainerJob on line 3 is technically an object as I need to use the non-generics overload to do the resolution (ie a Type parameter not an '(Of XXX)').

据调试器,但它实际上是一个 MyProject.Jobs.JobWrapper(中MyProject.Jobs.DailyStatusReport)

According to the debugger, however it's actually a MyProject.Jobs.JobWrapper(Of MyProject.Jobs.DailyStatusReport)

MyProject.Jobs.JobWrapper 器具 IJobWrapper(中IJob) MyProject.Jobs.DailyStatusReport 器具 IJob

在DirectCast引发此异常:

The DirectCast throws this exception:

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 中定义的接口的麻烦 - 但如果是这样的话,我不确定如何调和这两种。

Can someone please explain why it can't do the cast / how to get around it? I'm wondering if it is having trouble matching the Interface defined in the referenced assembly with the one referenced from within Jobs.dll - But if that is the case, I'm unsure how to reconcile the two.

非常感谢。

编辑:

从接口采样方法:

IJob:

Function ShouldExectute() As Boolean
Sub Execute()

IJobWrapper:

IJobWrapper:

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

例如 - 作业包装不会再回到anythign与IJob的类型。它使用类型信息来查找已连接到它实现IJob和读取信息类的各种属性。

Eg - The Job Wrapper doesn't ever return anythign with the type of the IJob. It does use the type information to look up various Attributes which have been attached to the class which implements IJob and read information.

推荐答案

这是不可能执行这个转换(有或没有反射),因为泛型类型参数都必须完全匹配。所以,你可以施放 AnyImplementationOfIJobWrapper(中IJob) IJobWrapper(中IJob),但你不能施放 AnyImplementationOfIJobWrapper(AnyImplementationOfIJob中) IJobWrapper(中IJob)

It is not possible to perform this cast (with or without reflection) because generic type parameters are required to match exactly. So you could cast an AnyImplementationOfIJobWrapper(Of IJob) to IJobWrapper(Of IJob), but you can not cast an AnyImplementationOfIJobWrapper(Of AnyImplementationOfIJob) to IJobWrapper(Of IJob).

不过,如果你控制了$ C $下 IJobWrapper ,你可以把它变成的 的宣布为接口IJobWrapper(出IJob)接口 。这将允许您执行转换。这是相同的机制,可以让你如分配的IEnumerable(子类)的IEnumerable(超类)

However, if you control the code for IJobWrapper, you can turn it into a covariant interface by declaring it as Interface IJobWrapper(Of Out IJob). This will allow you to perform the cast. It is the same mechanism that allows you to e.g. assign an IEnumerable(Of Subclass) to IEnumerable(Of Superclass).

(随时纠正任何语法错误,我可能会做;它已经有一段时间,因为我用VB)

(Feel free to correct any syntax mistakes I might have made; it's been a while since I used VB.)

有一个自然的问题是:为什么不投这个摆在首位允许吗?原因是,它会引发危险的情况:假设你有一个 IList的车辆(车辆)。这很自然,它应该是可以分配一个列表,(汽车)到车辆由于车名单可以考虑车辆的列表。但是,如果我们让指的是一个真正的列表(汽车),我们可以尝试添加,这应该因为车辆被允许出现为和列表的。然而,实际的列表限制为仅包含 s,因此我们必须要么抛出一个异常(很意外为车辆用户)或插入 S(创建一个等待发生的灾难)的列表。解决方法:禁止投。 的IEnumerable (而不是的IList )可协变的​​,因为它只包含的方法,可以让你从集合中读取。因此,的IEnumerable(车)可以被分配到一个的IEnumerable(车辆),因为的IEnumerable 只让你阅读的收集内容,而不是插入新的对象进去。

A natural question would be "Why is not this cast allowed in the first place?" The reason is that it would lead to dangerous situations: Assume that you have an IList(Of Vehicle) vehicles. It seems natural that it should be possible to assign a List(Of Car) to vehicles, since a list of cars could be considered a list of vehicles. But if we allow vehicles to refer to what is truly a List(Of Car), we could try to add a Boat to vehicles, which should be allowed since vehicles appears to be a list of Vehicles and a Boat is a Vehicle. However, the actual list is restricted to only contain Cars, so we must either throw an exception (very unexpected for the user of vehicles) or insert the Boat into a list of Cars (creating a disaster waiting to happen). Solution: disallow the cast. IEnumerable (but not IList) can be made covariant because it only contains methods that lets you read from the collection. Therefore, an IEnumerable(Of Car) can be assigned to an IEnumerable(Of Vehicle) because IEnumerable only lets you read contents of the collection, not insert new objects into it.

这篇关于使用反射然后铸造.NET泛型加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆