.Net加载泛型使用反射然后铸造

时间:2011-02-22 11:37:03

标签: generics reflection .net-4.0 unity-container

这是this question的后续行动。如果你对背景故事感兴趣,那就麻烦阅读。

简而言之,我使用反射从程序集中加载一组泛型类型。程序集在运行时加载。

我有一个第二个程序集,由我当前的项目和我正在加载的包含接口的程序集引用:

  • IJob
  • IJobWrapper(Of IJob)

我正在加载的程序集(称之为Jobs.dll)包含JobWrapper(Of IJob) - 它实现了IJobWrapper接口。

Jobs.dll还包含多个实现IJob

的作业

现在,我正在将相应的类型加载到容器(Unity)中,并在需要时将它们拉出来。这有效(也就是说,容器会根据需要解析引用并实例化对象)

注意:下面的JobTypeJobWrapperType是通过反思检索的。

具体做法是:

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

这里抛出的错误是演员的最后一行。

第3行的

ContainerJob在技术上是一个对象,因为我需要使用非泛型重载来执行解析(即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 个答案:

答案 0 :(得分:2)

无法执行此强制转换(使用或不使用反射),因为要求通用类型参数完全匹配。因此,您可以将AnyImplementationOfIJobWrapper(Of IJob)投射到IJobWrapper(Of IJob),但无法将AnyImplementationOfIJobWrapper(Of AnyImplementationOfIJob)投射到IJobWrapper(Of IJob)

但是,如果您控制IJobWrapper的代码,则可以将其声明为Interface IJobWrapper(Of Out IJob),将其变为covariant interface。这将允许您执行演员表。这是允许你进行相同的机制。将IEnumerable(Of Subclass)分配给IEnumerable(Of Superclass)

(请随意纠正我可能犯的任何语法错误;自从我使用VB以来已经有一段时间了。)

一个自然的问题是“为什么不首先允许这种演员?”原因是它会导致危险的情况:假设你有一个IList(Of Vehicle) vehicles。似乎很自然的是,应该可以将List(Of Car)分配给vehicles,因为汽车列表可以被视为车辆列表。但是,如果我们允许vehicles引用真正属于List(Of Car)的内容,我们可以尝试将Boat添加到vehicles,自vehicles以来应该允许Vehicle似乎是Boat的列表,而VehicleCar。但是,实际列表仅限于包含vehicles,因此我们必须抛出异常(Boat的用户非常意外)或将Car插入IEnumerable列表中{1}} s(造成等待发生的灾难)。解决方案:禁止演员。 IList(但不是IEnumerable(Of Car))可以变为协变,因为它只包含允许您从集合中读取的方法。因此,可以将IEnumerable(Of Vehicle)分配给IEnumerable,因为{{1}}只允许您阅读集合的内容,而不是将新对象插入其中。