Vb.net 如何创建与嵌套类型参数的子类一起工作的扩展方法?

Vb.net 如何创建与嵌套类型参数的子类一起工作的扩展方法?,vb.net,inheritance,extension-methods,type-parameter,Vb.net,Inheritance,Extension Methods,Type Parameter,我在访问我创建的一个扩展方法时遇到了问题,该方法将一个具有基类的对象作为其类型参数 下面是基类: Namespace Models.Db 公共阶级基础 作为整数的公共属性Id 末级 结束命名空间 …以及子类: Namespace Models.Db 公营城市 继承基础 ... 末级 结束命名空间 以下是扩展方法: 导入System.Collections.Generic 导入System.Data.Entity 导入系统 导入System.Runtime.CompilerServices 导

我在访问我创建的一个扩展方法时遇到了问题,该方法将一个具有基类的对象作为其类型参数

下面是基类:

Namespace Models.Db
公共阶级基础
作为整数的公共属性Id
末级
结束命名空间
…以及子类:

Namespace Models.Db
公营城市
继承基础
...
末级
结束命名空间
以下是扩展方法:

导入System.Collections.Generic
导入System.Data.Entity
导入系统
导入System.Runtime.CompilerServices
导入矩阵。模型
进口最低起订量
公共模块扩展
公共子SetupMock(实例为Mock(属于DbSet(属于Db.Base)),实体为List(属于Db.Base))
Instance.As(属于IQueryable(属于Db.Base)).Setup(函数(Cities)Cities.GetEnumerator).Returns(Entities.GetEnumerator)
Instance.As(属于IQueryable(属于Db.Base)).Setup(函数(Cities)Cities.ElementType).返回(Entities.AsQueryable.ElementType)
Instance.As(属于IQueryable(属于Db.Base)).Setup(函数(Cities)Cities.Expression)。返回(Entities.AsQueryable.Expression)
Instance.As(属于IQueryable(属于Db.Base)).Setup(函数(Cities)Cities.Provider).返回(Entities.AsQueryable.Provider)
端接头
端模块
…以下是呼叫代码:

私有函数GetDbContextMock()作为Mock(Db.Context的)
Dim oCitiesMock作为Mock(属于数据库集(属于数据库城市))
oCitiesMock=新模拟(数据库集的(数据库城市的))
oCitiesMock.SetupMock(Me.Cities)'Me.Cities是(Db.City)列表
端函数
编译时错误为:

“SetupMock”不是“Mock(属于DbSet(属于城市))”的成员

但是,当我将调用代码更改为:

Dim oCitiesMock作为Mock(DbSet的(Db.Base的))
oCitiesMock=新的Mock(数据库集的)(数据库基的))
…找到了扩展方法。但是我需要向扩展方法发送一个子类引用,而不是基类引用

指示可以使用简单的超类/子类对象,但由于这是处理类型参数,所以有点复杂

起初似乎它可能提供了一个解决方案,但经过进一步思考,它只处理了一个级别的类型参数。上面的代码有两个。我不确定这种细微差别是否会产生影响,但最终代码无法编译


这可以在.NET中完成吗?

您的第二个链接答案是正确的。额外的打字“水平”其实并不重要。这个答案的关键点是,在使用派生类型定义扩展方法时,包括泛型(
在C#中,
(在VB中)
)。您最初的代码并没有做到这一点-期望基类型是很难编码的

当以这种方式使用泛型时,可以添加一个约束,以便
T
必须继承所需的基类型。(从技术上讲,这适用于任何泛型方法,因此扩展方法也以这种方式工作很方便。)

请参见下面的控制台应用程序,以方便测试:

Option Strict On
Imports System.Runtime.CompilerServices

Module Module1
    Sub Main()
        Dim mock As New Mock(Of [Set](Of Derived))
        mock.SetupMock(New List(Of Derived))

        'also compiles, uses same extension
        Dim mockBase As New Mock(Of [Set](Of Base))
        mockBase.SetupMock(New List(Of Base))
    End Sub
End Module

Public Module Extensions
    <Extension>
    Public Sub SetupMock(Of T As Base)(Instance As Mock(Of [Set](Of T)), Entities As List(Of T))
        'do stuff with Entities
    End Sub
End Module

'simple class definitions to illustrate the example
Public Class Base : End Class
Public Class Derived
    Inherits Base
End Class
Public Class [Set](Of T) : End Class
Public Class Mock(Of T) : End Class
选项严格打开
导入System.Runtime.CompilerServices
模块1
副标题()
Dim mock作为新的mock(属于[集合](属于派生的))
mock.SetupMock(新列表(派生的))
'还编译,使用相同的扩展名
Dim mockBase作为新模型(共[套](共基础))
mockBase.SetupMock(新列表(基础))
端接头
端模块
公共模块扩展
公共子SetupMock(以T为基础)(实例为Mock(以[Set](以T为基础)),实体为列表(以T为基础))
“用实体做东西
端接头
端模块
'用于说明示例的简单类定义
公共类基类:结束类
公共类派生
继承基础
末级
公共类[集](共T个):最终类
公共类Mock(Of T):结束类

如果您的实体列表始终是基本类型的列表,但恰好是用派生类型填充的,那么您可以使用
实体将扩展方法定义为list(of Base)
,但是您的列表最好始终是
list(of Base)
,而不是
list(of T)

,谢谢。最后,我不得不在
实体作为List(Of T)
实体作为IEnumerable(Of Db.Base)
之间进行选择。我和前者一起去的。看起来更性感。@InteXX IEnumerable(Of T)更灵活。(我试图双关灵活和性感;没有什么好结果。)@InteXX注意,
IEnumerable
的参数是可变的(我相信你可以使用
IEnumerable(派生的)
,其中
IEnumerable(基础的)
是预期的——我忘了这是协方差还是逆变)。差异可能会在这里起作用,我建议你读一读。事实上,最后我两个都不能用。我的两个实体——
角色
用户
——不是从
基础
派生出来的,而是分别从
标识列表
标识用户
派生出来的。我无法更改的其他代码明确要求使用Db.RoleDb.User类型,因此我不得不完全跳过扩展方法。但是,是的,在我的角色扮演过程中,我确实注意到,
IEnumerable(Of T)
似乎工作得更好。谢谢你的提醒@CraigOK,我把扩展方法带回来了。我将方法的类型参数从
Setup(TEntity作为Db.Base)
修改为
Setup(TEntity作为类)
。这将处理
Db.Base
以及
IdentityRole
IdentityUser
。效果很好@克雷格