【问题标题】:.Net Loading Generics using Reflection then Casting.Net 使用反射然后投射加载泛型
【发布时间】:2011-02-22 20:21:49
【问题描述】:

这是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 在技术上是一个对象,因为我需要使用非泛型重载来进行解析(即类型参数不是“(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 中引用的接口匹配时遇到问题 - 但如果是这种情况,我不确定如何协调两者。

非常感谢。

编辑:

来自接口的示例方法:

我的工作:

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 并读取信息的类的各种属性。

【问题讨论】:

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


    【解决方案1】:

    由于泛型类型参数需要完全匹配,因此无法执行此强制转换(有或没有反射)。所以你可以将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 似乎是Vehicles 的列表BoatVehicle。但是,实际列表仅限于包含 Cars,因此我们必须要么抛出异常(对于 vehicles 的用户来说非常意外),要么将 Boat 插入到 Cars 的列表中(创建一个灾难等待发生)。解决方案:禁止演员表。 IEnumerable(但不是IList)可以成为协变的,因为它只包含允许您从集合中读取的方法。因此,IEnumerable(Of Car) 可以分配给IEnumerable(Of Vehicle),因为IEnumerable 只允许您读取集合的内容,而不能向其中插入新对象。

    【讨论】:

    • 好的,这似乎正是我遇到的问题(奇怪的是我以前从未遇到过)。我确实控制了Jobs.dll - 你能举个例子说明完成这项工作所需的代码吗?
    • 如果有帮助,我会将接口上的方法摘要添加到我的问题中
    • 我假设您对IJobWrapper 的声明如下所示:Interface IJobWrapper(Of IJob)。在这种情况下,添加关键字Out 就足以使接口协变:Interface IJobWrapper(Of Out IJob)。但是,协变和逆变是在 .NET 4.0 中引入的,并且可能在早期版本中不起作用。
    • 谢谢,我试试。幸运的是,我使用的是 .Net 4
    • 工作得很好,谢谢 - 现在我只需要离开并了解它在做什么......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多