2016-09-30 1 views
1

Ich portiere Tests eines nicht-generischen Repository zu einem generischen. Anstatt Repo<MyType> zu verwenden, möchte ich die abstrakteren Methoden mit Repo<object> oder so etwas testen.Wie erstellt man eine anonyme Klasse, damit sie an einen generischen Konstruktor übergeben werden kann?

Ich habe versucht, eine anonyme Instanz, zu verwenden, aber es hat nicht funktioniert:

[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 
    } 

Ich habe versucht, die Klassenreferenz von dem Objekt zu schließen, ohne Erfolg zu:

 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); 

Wie kann ich das lösen? Ich beanspruche keine anonymen Objekte, ich dachte nur, es wäre ein pragmatischer Weg, um meine Tests laufen zu lassen, aber ich könnte es auch anders machen, wenn das kein gutes Design ist.

+1

Statt 'object' als generische Typ, versuchen' dynamic' zu verwenden, Sie sollten in der Lage sein, auf Ihre Eigenschaft 'Name' zuzugreifen. –

Antwort

1

Statt dessen:

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

Machen Sie eine generische Methode Repository zu erstellen:

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

Verbrauch:

[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 
} 

Durch Ihr anonymes Objekt als Parameter übergeben wird (auch wenn Sie verwenden es nicht), es ermöglicht Ihnen, seinen Typ als generisches Argument zu erhalten. Anschließend können Sie die Objekte abhängig von ihrem Typ instanziieren.

+0

In einer Testsituation macht dies den Aufbau der Vorrichtung ein wenig komplizierter. Ich habe am Ende eine "TestObject" -Klasse erstellt und werde sie anstelle von anonym verwenden, da ich denke, dass dies das richtige Design für meine Situation ist, aber ich denke, dass deine Antwort das am besten behandelt, was ich gefragt habe. Vielen Dank!! – heltonbiker

1

Der einfachste Weg für fix ist dieser über eine generische Methode obj mit dem Compiler zu bekommen in die Lücken zu füllen:

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

... 

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

Jetzt T der anonyme Typ ist.

+0

Sobald OP auf die Eigenschaften dieses anonymen Typs zugreifen möchte, bleibt er hängen, da sie zur Kompilierzeit nicht erkannt werden. Fur Serialisierung ist das natürlich nicht so wichtig. – HimBromBeere

2

Der Trick mit anonymen Typen ist, durch Beispiel zu werfen; lassen Sie den Compiler die Arbeit für Sie tun, indem Sie Typinferenz nutzen:

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

Alles was Sie jetzt tun müssen, ist:

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

Ich mag das, aber die einzige Con, die ich sehe, ist, wann immer Sie auf die Eigenschaften des Objekts zugreifen wollen, müssen Sie es umwandeln. Dann, wenn Sie Ihren Container bekommen, wissen Sie nicht unbedingt, für welchen Typ "Objekt" steht. Also, für jemanden, der in Ihren Code einsteigt, kann es etwas verwirrend sein. Trotzdem sollte es in diesem Fall kein Problem geben. –

+0

@ romain-aga Nun, man könnte argumentieren, dass man immer einen gültigen Referenztyp des Artikels kennt, den man aus einem Repo holt; Wie würdest du den geholten Gegenstand sonst benutzen? – InBetween

+0

Ich kann es nicht leugnen, du hast Recht in diesem Fall. Selbst wenn Sie sich einige seltsame Implementierungen vorstellen könnten. Im allgemeinen Fall, wenn Sie anonyme Typen in einer generischen Klasse speichern, kann es zu einem Problem kommen. –

Verwandte Themen