Generics .Net使用反射然后强制转换加载泛型
这是一项后续行动。只有当你对背景故事感兴趣的时候,才懒得去读它 简而言之,我使用反射从程序集加载一组泛型类型。程序集在运行时加载 我的当前项目和正在加载的程序集都引用了第二个程序集,该程序集包含以下接口:Generics .Net使用反射然后强制转换加载泛型,generics,reflection,.net-4.0,unity-container,Generics,Reflection,.net 4.0,Unity Container,这是一项后续行动。只有当你对背景故事感兴趣的时候,才懒得去读它 简而言之,我使用反射从程序集加载一组泛型类型。程序集在运行时加载 我的当前项目和正在加载的程序集都引用了第二个程序集,该程序集包含以下接口: IJob IJob包装器(IJob的) 我正在加载的程序集(称之为Jobs.dll)包含一个JobWrapper(IJob的)——它实现了IJobWrapper接口 Jobs.dll还包含多个实现IJob 现在,我将适当的类型加载到一个容器(Unity)中,并在需要时将其取出。这是可行的(
IJob
IJob包装器(IJob的)
Jobs.dll
)包含一个JobWrapper(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))
这里抛出错误的是演员阵容的最后一行
第3行的ContainerJob
在技术上是一个对象,因为我需要使用非泛型重载来进行解析(即类型参数而不是“(Of XXX)”
然而,根据调试器,它实际上是一个MyProject.Jobs.JobWrapper(MyProject.Jobs.DailyStatusReport的)
MyProject.Jobs.JobWrapper
实现IJobWrapper(IJob的)
MyProject.Jobs.DailyStatusReport
ImplementsIJob
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:
IJobWrapper:
Function ShouldExectute() As Boolean
Sub Execute()
ReadOnly Property DatabaseId as Long
ReadOnly Property Name as String
ReadOnly Property IsDisabled As Boolean
作业包装器永远不会返回IJob类型的任何东西。它确实使用类型信息来查找附加到实现IJob和读取信息的类的各种属性 不可能执行此强制转换(带反射或不带反射),因为需要泛型类型参数精确匹配。因此,您可以将
AnyImplementationOfIJobWrapper(属于IJob)
强制转换为IJobWrapper(属于IJob)
,但您不能将AnyImplementationOfIJobWrapper(属于IJob)
强制转换为IJobWrapper(属于IJob)
但是,如果您控制IJobWrapper
的代码,则可以通过将其声明为接口IJobWrapper(Out IJob)
将其转换为。这将允许您执行演员阵容。这与允许您将IEnumerable(子类的)
分配给IEnumerable(超类的)
的机制相同
(请随意更正我可能犯的任何语法错误;我已经有一段时间没有使用VB了。)
一个自然的问题是“为什么一开始就不允许使用此类型?”原因是它会导致危险情况:假设您有一辆
IList(Of Vehicle)vehicles
。似乎可以将列表(汽车)
分配给车辆
,因为汽车列表可以被视为车辆列表。但是如果我们允许车辆
引用真正的车辆列表
,我们可以尝试将船
添加到车辆
,这应该是允许的,因为车辆
似乎是车辆
的列表,而船
是车辆
。但是,实际列表仅限于包含汽车
s,因此我们必须抛出一个异常(对于车辆
的用户来说非常意外),或者将船
插入汽车
的列表(造成等待发生的灾难)。解决方案:禁止演员阵容IEnumerable
(但不是IList
)可以成为协变的,因为它只包含允许从集合中读取的方法。因此,可以将IEnumerable(汽车)
分配给IEnumerable(汽车)
,因为IEnumerable
只允许您读取收藏的内容,而不允许在其中插入新对象。好吧,这似乎正是我遇到的问题(我以前从未奇怪地遇到过)。我确实控制着Jobs.dll
-你能给出一个实现这项功能所需的代码示例吗?如果有帮助,我会在我的问题中添加一个关于接口的方法摘要。我假设你对IJobWrapper
的声明如下所示:接口IJobWrapper(IJob的)
。在这种情况下,添加关键字Out
即可使接口协变:interface IJobWrapper(Of Out IJob)
。然而,协变和逆变是在.NET4.0中引入的,在早期版本中可能不起作用。谢谢,我将尝试一下。幸运的是,我使用的.Net 4工作得很好,谢谢-现在我只需要离开去了解它在做什么。。。
Function ShouldExectute() As Boolean
Sub Execute()
ReadOnly Property DatabaseId as Long
ReadOnly Property Name as String
ReadOnly Property IsDisabled As Boolean