| 

.NET C# Java Javascript Exception

3
Guten Morgen,

ich "spiele" gerade mit DI per Unity bzw. MEF im Zusammenhang mit Repositories und UnitOfWork herum. Ich glaube, so langsam habe ich das Prinzip verstanden und hätte aber ganz gerne eine kurze abschließende Bestätigung über mein Verständnis einer bestimmten Verhaltensweise von DI-Containern.

Angenommen, ich hätte 2 Repositories A und B.
Beiden Klassen wird im Konstrukture eine IUnitOfWork übergeben.

Nun habe ich z.B. in meinem ViewModel folgenden Code:

var a = IoC.Resolve(Of IRepositoryA)()
var b = IoC.Resolve(Of IRepositoryB)()


In diesem Fall würde, je nach Konfiguration, die UnitOfWork u.U. 2 mal instanziiert,
wenn es z.B. als Singleton konfiguriert ist. Oder auch nur ein einziges mal. Soweit klar für mich.

Wenn ich nun aber eine Constructor-Injection habe wie z.B.
Public Void Initialize(IRepositoryA repoA, IRepositoryB repoB) { }

dann hat es beim testen von Unity den Anschein auf mich, das nur eine Instanz der UnitOfWork erzeugt wird und beide Repositories dann dieselbe Instanz benutzen. Selbst, wenn ich es als Singleton konfiguriere.

Wäre für mich auch logisch, da ja beide im selben Konstruktor injiziert werden und ich das Verhalten (1 UOW oder 2 UOW) so beeinflussen kann. Ich finde allerdings in der Hilfe zu Unity nichts darüber und hätte ganz gerne von Euch bestätigt, das generell alle DI-Container auf diese Art und Weise arbeiten.

Danke schon einmal im Voraus,
Jens
News:
22.12.2011
Jens Duczmal 2,6k 1 3 9
*hust* Es kann doch nicht sein, das hier keiner die Antwort weiss, oder? Die Frage erscheint ja sogar mir recht simpel :)
Jens Duczmal 11.01.2012
Dann beantworte sie doch! :)
LiRo 11.01.2012
Hm, so einfach erscheint mir das nicht. Ich traue mir jedenfalls keine Aussage über "generell alle DI-Container" zu. Die beiden, mit denen ich praktische Erfahrung habe, sind Spring und LightCore. Bei Spring sind Singletons der Default, d.h. diese Objekte gibt es genau einmal. Bei LightCore sind Multitons der Standard. Wie sich der in dem Fall verhält, habe ich noch nicht ausprobiert, aber es wäre mir eigentlich egal - wenn ich mit Multitons arbeite und die Objekte auch noch vom DI-Container automatisch bereitgestellt werden, sollte Objektidentität keine große Rolle für den Code spielen.
Matthias Hlawatsch 11.01.2012
1 Antwort
0
Eine pauschale Antwort ist hier nicht möglich.
Ich z.B. finde es alles andere als logisch, dass per DI die gleiche UnitOfWork von zwei verschiedenen Repositories genutzt wird. Thema: SOLID.

Bist du Dir wirklich sicher, dass die gleiche Instanz genutzt wird?

"Selbst, wenn ich es als Singleton konfiguriere"

Diese Aussage macht mich stutzig. Singleton bedeutet, dass nur eine Instanz vorhanden sein darf. Jede Anfrage an den Container oder über DI/PI gibt die gleiche Instanz wieder! Versteh mich bitte nicht falsch, aber vielleicht hast du da Factory mit Singleton vertauscht?

Ich habe es mal in C# und mit Autofac, welches meiner Meinung nach das beste Framework ist, nachgebildet.

Tests
[Test]
public void TestUnitOfWorkIsSingleton()
{
var builder = new ContainerBuilder();

builder.RegisterType<RepositoryLocator>();
builder.RegisterType<UnitOfWork>().SingleInstance().AsImplementedInterfaces();
builder.RegisterType<RepositoryA>().AsImplementedInterfaces();
builder.RegisterType<RepositoryB>().AsImplementedInterfaces();

var container = builder.Build();

var repositoryA = container.Resolve<IRepositoryA>();
var repositoryB = container.Resolve<IRepositoryB>();
var repositoryLocator = container.Resolve<RepositoryLocator>();

Assert.AreEqual(repositoryA.UnitOfWork, repositoryB.UnitOfWork);
Assert.AreEqual(repositoryLocator.RepositoryA.UnitOfWork, repositoryLocator.RepositoryB.UnitOfWork);
}

[Test]
public void TestUnitOfWorkFactory()
{
var builder = new ContainerBuilder();

builder.RegisterType<RepositoryLocator>();
builder.RegisterType<UnitOfWork>().AsImplementedInterfaces();
builder.RegisterType<RepositoryA>().AsImplementedInterfaces();
builder.RegisterType<RepositoryB>().AsImplementedInterfaces();

var container = builder.Build();

var repositoryA = container.Resolve<IRepositoryA>();
var repositoryB = container.Resolve<IRepositoryB>();
var repositoryLocator = container.Resolve<RepositoryLocator>();

Assert.AreNotEqual(repositoryA.UnitOfWork, repositoryB.UnitOfWork);
Assert.AreNotEqual(repositoryLocator.RepositoryA.UnitOfWork, repositoryLocator.RepositoryB.UnitOfWork);
}


Interfaces:
public interface IUnitOfWork
{

}

public interface IRepositoryA
{
IUnitOfWork UnitOfWork { get; set; }
}

public interface IRepositoryB
{
IUnitOfWork UnitOfWork { get; set; }
}


Implementation:
public class UnitOfWork : IUnitOfWork
{

}

public class RepositoryA : IRepositoryA
{
public IUnitOfWork UnitOfWork { get; set; }

public RepositoryA(IUnitOfWork unitOfWork)
{
this.UnitOfWork = unitOfWork;
}
}

public class RepositoryB : IRepositoryB
{
public IUnitOfWork UnitOfWork { get; set; }

public RepositoryB(IUnitOfWork unitOfWork)
{
this.UnitOfWork = unitOfWork;
}
}

public class RepositoryLocator
{
public IRepositoryA RepositoryA { get; set; }
public IRepositoryB RepositoryB { get; set; }

public RepositoryLocator(IRepositoryA repositoryA, IRepositoryB repositoryB)
{
this.RepositoryA = repositoryA;
this.RepositoryB = repositoryB;
}
}


Das die Repositories bzw. die UnitOfWorks public sind, ist nur für die Tests. Normalerweise würde ich es anständig mocken, aber zur Veranschaulichung reicht es ja.

Test 1:
- Die UnitOfWork wird als Singleton registriert.
=> Beide Repositories erhalten die gleiche Instanz.

Test 2:
- Die UnitOfWork wird Factory registriert (Default bei Autofac, sofern man nichts anderes angibt)
=> Beide Repositories erhalten unterschiedliche Instanzen.

Edit:
Da habe ich doch glatt mein Fazit vergessen ;)
Jedes IoC Framework arbeitet ähnlich, jedoch nicht gleich. Daher ist eine pauschle Aussage nicht möglich, ich bezweifel allerdings sehr stark das Unity so funktioniert wie du es beschrieben hast.
30.03.2012
mkernbach 11 2

Stelle deine Instanz-Frage jetzt!