2016-09-30 1 views
1

私は非汎用リポジトリのテストを一般的なものに移植しています。 Repo<MyType>を使用する代わりに、より抽象的なメソッドをRepo<object>などでテストしたいと考えています。ジェネリックコンストラクタに渡すことができるように匿名クラスを作成する方法は?

私は匿名インスタンスを使用しようとしましたが、それはうまくいきませんでした:

[Test] 
    public void AddToRepoIncrementsByOne() 
    { 
     IFile file = new FileFake(); 
     IByteSerializer<object> serializer = new SerializerObjectFake(); 
     repo = new WriteableFileRepository<object>(file, serializer); 

     var obj = new { Name = "test" }; 
     repo.Add(obj); 

     Assert.True(repo.Items.Count() == 1); 
     Assert.AreEqual(repo.Items.Single().Name, obj.Nome); 
     //----------------------------------^^^^ 
     //-------------------compiler error here 
    } 

私はあまりにも成功せず、オブジェクトからクラス参照を推測しようとした:

 var obj = new { Nome = "teste" }; 

     Type T = obj.GetType(); 

     IArquivo arquivo = new ArquivoFake(); 
     IByteSerializer<T> serializer = new SerializerObjectFake(); 
     //--------------^ 
     repo = new RepositórioArquivoEscrita<T>(arquivo, serializer); 

これをどうすれば解決できますか?私は匿名のオブジェクトを使用することを要求していない、私はちょうどそれが私のテストを実行させるための実用的な方法だろうと思ったが、これは良い設計でない場合は確かに他の方法を行うことができます。

+1

代わりに 'のジェネリック型としてobject'、' dynamic'を使用しよう:今、すべてを行う必要がある

public static T CastByExample(this object obj, T prototype) => (T)obj; 

:型推論活用することで、コンパイラがあなたのために仕事をさせあなたはあなたのプロパティ 'Name'にアクセスできるはずです。 –

答えて

1

IByteSerializer<object> serializer = new SerializerObjectFake(); 
repo = new WriteableFileRepository<object>(file, serializer); 

があなたのリポジトリを作成する一般的な方法を行います。

RepoType<T> CreateRepository<T>(IFile file, T objectForType) 
{ 
    IByteSerializer<T> serializer = new SerializerObjectFake(); 
    return new WriteableFileRepository<T>(file, serializer); 
} 

使用法:

[Test] 
public void AddToRepoIncrementsByOne() 
{ 
    IFile file = new FileFake(); 
    var obj = new { Name = "test" }; 
    /*Your type is missing*/ repo = CreateRepository(file, obj); 

    repo.Add(obj); 

    Assert.True(repo.Items.Count() == 1); 
    Assert.AreEqual(repo.Items.Single().Name, obj.Nome); 
    //----------------------------------^^^^ 
    //-------------------no more error here 
} 

場合でも(パラメータとして、あなたの匿名オブジェクトを渡すことで、あなたはそれを使用しません)、それは汎用引数としてその型を得ることができます。次に、そのタイプに応じてオブジェクトをインスタンス化するために使用することができます。

+0

テスト状況では、これにより、フィクスチャセットアップが少し複雑になります。私は 'TestObject'クラスの作成を終了し、匿名の代わりにこのクラスを使用します。これは私の状況のた​​めの正しいデザインだと思っています。ありがとう!! – heltonbiker

1

修正のための最も簡単な方法は、これは空白を埋めるようにコンパイラを取得するためにobjを使用して、一般的なメソッドを介してである:今

var obj = new { Nome = "teste" }; 
Foo(obj); 

... 

void Foo<T>(T obj) { 
    IArquivo arquivo = new ArquivoFake(); 
    IByteSerializer<T> serializer = new SerializerObjectFake(); 
    // etc 
} 

Tは匿名型です。これに代えて

+0

OPは、コンパイル時にunknwonであるので、彼が固執しているその匿名型のプロパティにアクセスするとすぐにとにかくです。ただし、これは重要ではありません。 – HimBromBeere

2

匿名の種類のトリックは、例でキャストすることです。 、

Assert.AreEqual(repo.Items.Single().CastByExample(obj).Name, obj.Name); 
+0

私はこれが好きですが、オブジェクトのプロパティにアクセスするときはいつでも、それをキャストする必要があります。そして、あなたがコンテナを取得したとき、あなたはどのような型の 'オブジェクト'が何を表しているか分かりません。だから、あなたのコードに入る人にとっては、ちょっと混乱するかもしれません。しかし、この場合、問題ではありません。 –

+0

@ romain-agaまあ、あなたはレポから取り出しているアイテムの有効な参照タイプを常に知っていると主張できます。そうでなければ、取り出されたアイテムをどのように使用しますか? – InBetween

+0

私はそれを否定することはできません、あなたはそうです。たとえあなたが奇妙な実装を想像できるのであれば、もっと一般的なケースでは、ジェネリッククラスに匿名型を格納するときに問題が発生する可能性があります。 –

関連する問題