这就是我所拥有的(使用Rhino Mocks,但这不是问题的核心):
var entityMock = MockRepository.GenerateMock<IEntity>();
this.Cache = MockRepository.GenerateStub<Cache<IEntity>>();
是否可以更具体地设置Cache<T>
的类型参数?类似的东西:
var entityMock = MockRepository.GenerateMock<IEntity>();
this.Cache = MockRepository.GenerateStub<Cache<typeof(entityMock)>>();
当然这不编译。但是,如果可能的话,我想使用Rhino Mocks生成的类型,这是IEntity
的具体实现。
答案 0 :(得分:2)
请注意,虽然提到了RhinoMocks,但 仅 特定部分是GenerateStub
,它围绕提供的类型创建了一个具体的实现;其余的是不可知的RhinoMocks。
通用类型参数在编译时解析 - 如您所知;这不允许在没有反射的情况下在线输入类型作为泛型参数(即:var list = new List<typeof(int)>();
)。
但是,您可以使用反射创建泛型类型。在本质上,如果您可以通过以下方式获取动态代理的类型:
var entityMock = MockRepository.GenerateMock<IEntity>();
var dynamicType = entityMock.GetType();
MockRepository
有一个GenerateStub
,其中包含Type
和object[]
个参数,因此从上面继续:
var cacheType = typeof(Cache<>);
var genericType = cacheType.MakeGenericType(dynamicType);
var stubbed = MockRepository.GenerateStub(genericType, null);
遗憾的是,stubbed
项的类型为object
,但正如Lucero在评论中所述,可以使用通用协方差来获得比{{1}更有用的类型}。我在下面演示了这一点。
<小时/> 基于与Lucero的有趣讨论,如果您定义一个新的
object
接口来表示Cache,那么通用协方差将允许您将生成的代理转换为基类型(ICache<out T>
) :
ICache<IEntity>
答案 1 :(得分:2)
您可以在运行时使用反射创建一个封闭的泛型类型。问题是你很可能只需要使用反射继续操作它,因为(鉴于它的类型在编译时是未知的)你不能把它当作可直接使用的东西。
例如,要创建“某事”列表:
public IList CreateList(Type t)
{
var openListType = typeof(List<>);
return (IList)openListType.MakeGenericType(t);
}
这个例子说明了几个要点:
CreateList
无法接受t
作为通用类型参数,仍然允许相同的功能。object
以外的任何其他内容。在这里,我们知道我们将始终创建一个IList
,所以事情会好一些。我没有Rhino Mocks的经验,但在你的情况下,它会转化为:
var entityMock = MockRepository.GenerateMock<IEntity>()
var cacheType = typeof(Cache<>).MakeGenericType(entityMock.GetType());
this.Cache = MockRepository.GenerateStub(cacheType);
...但仅当适当的GenerateStub
重载可用时才会显示。
答案 2 :(得分:0)
如果代码希望根据泛型类型是否满足某些约束来执行不同的操作,特别是如果泛型类型中的某些操作甚至无法编译,则在某种程度上使用模式可能会有所帮助与Comparer<T>
和EqualityComparer<T>
等类使用的类似。诀窍是使用一个带有泛型参数T
的静态类,它将静态委托保存到一个参数类型为T
的方法,并且具有静态方法,每个方法都采用可能受限制的方法类型U
的通用参数,并且具有与U
匹配T
时与上述代理兼容的签名。第一次尝试使用静态类或其委托时,泛型类的静态构造函数可以使用Reflection来构造应该用于该类型的方法的委托。如果尝试以违反其一般约束的方式构造泛型方法的委托,则此类调用将在运行时失败;因为静态构造函数中的exceptioins非常糟糕,所以应该确保使用有效函数构造一个委托。另一方面,一旦委托构建一次,所有未来的呼叫都可以直接通过该代表发送,而无需进一步反思或类型检查。