RhinoMocksについて言及されていますが、特定の部分は、提供されたタイプの周りに具体的な実装を作成することだけであることに注意してください。GenerateStub
残りはRhinoMocksにとらわれません。
ご存知のように、ジェネリック型の引数はコンパイル時に解決されます。これにより、リフレクションなしでインラインで一般的な引数として型を入力することはできません(例:) var list = new List<typeof(int)>();
。
ただし、リフレクションを使用してジェネリック型を作成できます。本質的に、動的プロキシのタイプを次のようなものから取得できる場合:
var entityMock = MockRepository.GenerateMock<IEntity>();
var dynamicType = entityMock.GetType();
MockRepository
と引数GenerateStub
を取るaがあるので、上から続けます。Type
object[]
var cacheType = typeof(Cache<>);
var genericType = cacheType.MakeGenericType(dynamicType);
var stubbed = MockRepository.GenerateStub(genericType, null);
stubbed
アイテムは残念ながらタイプですが、object
Luceroがコメントで述べているように、一般的な共分散を使用して、単なるよりも使いやすいタイプを取得することができますobject
。これを以下に示します。
Luceroとの興味深い議論に基づいて
ICache<out T>
、キャッシュを表す新しいインターフェイスを定義すると、一般的な共分散により、結果のプロキシを(の
ICache<IEntity>
)ベースタイプにキャストできるようになります。
class Program
{
static void Main(string[] args)
{
// The concrete entity.
IEntity entityMock = MockRepository.GenerateMock<IEntity>();
entityMock.Stub(s => s.Name).Return("Adam");
// The runtime type of the entity, this'll be typeof(a RhinoMocks proxy).
Type dynamicType = entityMock.GetType();
// Our open generic type.
Type cacheType = typeof(ICache<>);
// Get the generic type of ICache<DynamicProxyForIEntity> (our closed generic type).
Type genericType = cacheType.MakeGenericType(dynamicType);
// Concrete instance of ICache<DynamicProxyForIEntity>.
object stubbed = MockRepository.GenerateStub(genericType, null);
// Because of the generic co-variance in ICache<out T>, we can cast our
// dynamic concrete implementation down to a base representation
// (hint: try removing <out T> for <T> and it will compile, but not run).
ICache<IEntity> typedStub = (ICache<IEntity>)stubbed;
// Stub our interface with our concrete entity.
typedStub.Stub(s => s.Item).Return(entityMock);
Console.WriteLine(typedStub.Item.Name); // Prints "Adam".
Console.ReadLine();
}
}
public interface ICache<out T>
{
T Item { get; }
}
public interface IEntity
{
string Name { get; }
}