Frage

Ich lerne gerade, wie Autofac zu verwenden, und ich bin fest mit IDisposable Entsorgung deterministisch-Objekte. Lassen Sie mich zunächst die Situation vorstellen, bevor ich mein Problem angeben.

Ausgangsposition:

sagen wir mein Objektmodell durch folgende Schnittstellen definiert:

interface IApple : IDisposable
{
    void Consume();
}

interface IHorse
{
    void Eat(IApple apple);   // is supposed to call apple.Consume()
}

interface IHorseKeeper
{
    void FeedHorse();   // is supposed to call horse.Eat(apple)
                        //   where 'horse' is injected into IHorseKeeper
                        //   and 'apple' is generated by IHorseKeeper on-the-fly
}

Ferner definiere ich einen Delegierten, der als IApple Fabrik verwendet werden:

delegate IApple AppleFactory;

Autofac Konfiguration:

Nun würde ich die oben genannten Typen wie folgt registrieren - beachten Sie, dass ich den Code der beiden Klassen Apple und Horse bin weggelassen, da sie sind trivial zu implementieren:

var builder = new Autofac.ContainerBuilder();

builder.RegisterType<Apple>().As<IApple>();
builder.RegisterType<Horse>().As<IHorse>();
builder.RegisterType<HorseKeeper>().As<IHorseKeeper>();
builder.RegisterGeneratedFactory<AppleFactory>();

Mein Problem:

Ich weiß nicht recht, wie Methode IHorseKeeper.Feed zu implementieren. Hier ist, was ich derzeit haben:

class HorseKeeper : IHorseKeeper
{
    private readonly IHorse horse;
    private readonly AppleFactory appleFactory;

    public HorseKeeper(IHorse horse, AppleFactory appleFactory)
    //                 ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^
    //                         constructor injection
    {
        this.horse = horse;
        this.appleFactory = appleFactory;
    }

    public void FeedHorse()
    {
        using (var apple = appleFactory())
        {
            horse.Eat(apple);
        }  // <- Dispose() apple now (ASAP), as it's no longer needed!
    }
}

Dies ist die Art von Code Ich mag würde haben, da es vollständig Autofac unabhängig ist. Es könnte genauso gut mit einem anderen IoC-Container, solange AppleFactory funktioniert wie erwartet.

Da jedoch Autofac die AppleFactory für mich behandelt, wird es den Überblick über alle IApple Objekte es für mich produziert, und wollen sie daher selbst am Ende der Lebensdauer des Behälters Dispose. D. h., Wird die erzeugte apple zweimal entsorgt werden.

I IApple als .ExternallyOwned() nehme Registrierung ist keine praktikable Lösung, da es Fälle geben kann, wo es einfacher ist, zu lassen Autofac die Lebenszeit IApples behandeln.

deterministische Entsorgung mit Autofac die Schaffung eines verschachtelten Container erfordert mit container.BeginLifetimeScope(), aber ich will nicht diese innerhalb HorseKeeper.FeedHorse verwenden, da dann HorseKeeper auf Autofac abhängig wird, und ich möchte meinen Code IoC unabhängig halten.

Frage:

Wie implementiere ich HorseKeeper.FeedHorse in einem IoC (Autofac) -agnostic Art und Weise, während sichergestellt wird, dass on-the-fly erzeugt Objekte angeordnet ist richtig?

War es hilfreich?

Lösung

Die anderen Antworten hier sind aufschlussreich, aber haben ein Problem. In beiden Fällen, wenn Apple andere Abhängigkeiten hat, dass Bedarf zur Verfügung, nicht korrekt Bereinigung geschehen.

Autofac 2 bietet eine neue Funktion, um Hilfe hier, genannt „im Besitz von Instanzen“. Ich bemerkte, dass Ihr Registrierungscode Autofac ist 1.4, also, wenn Sie nicht in der Lage, mich zu aktualisieren wissen lassen (es gibt auch andere, weniger transparent, Wege, dies zu tun.)

Register Apple als üblich (extern nicht im Besitz):

builder.RegisterType<Apple>().As<IApple>();

Declare AppleFactory wie:

public delegate Owned<IApple> AppleFactory();

In Autofac 2, brauchen Sie nicht RegisterGeneratedFactory () mehr nennen - dies erfolgt automatisch

.

Dann in HorseKeeper, füttern das Pferd wie folgt aus:

public void FeedHorse()
{
    using (var apple = appleFactory())
    {
        horse.Eat(apple.Value);
    }
}

(Beachten Sie die .Value Eigenschaft des zugrunde liegenden IApple zu erhalten.

Am Ende des mit Block der Apfel, und alle seine Abhängigkeiten, werden gereinigt.

Alle anderen Komponenten, die IApple direkt verwenden (als Abhängigkeiten) das übliche Verhalten bekommen.

Andere Tipps

Der einzige Weg ist, um die Apple-Anmeldung mit dem ExternallyOwned Modifikator zu ändern. Dies weist Autofac nicht für die Entsorgung, das Objekt zu verfolgen, sondern lassen Sie jemand anderen (Code) für die Entsorgung behandeln. Aber wie Sie Zustand, werden Sie nun dafür sorgen, dass alle Instanzen von Apple manuell angeordnet sind, da Sie keine automatische Hilfe von Autofac bekommen.

builder.RegisterType<Apple>().As<IApple>().ExternallyOwned();

Mit dieser Anmeldung Ihres Feed-Code wird wie erwartet, aber.

Hinweis : auf der Diskussion, ob die Schnittstelle IDisposable erben sollte oder nicht: IMO, wenn eine Schnittstelle erbt IDisposable, ist dies ein Hinweis auf die „raubend“ Entwickler, dass die Instanz an einige entsorgt werden Zeitpunkt. Im Fall von IApple, da diese Schnittstelle auch IDisposable ist, sollte der Entwickler sicherstellen, dass Verfügungs Instanzen (und Muss auch dann als ExternallyOwned registriert werden). Auf der anderen Seite sah, wenn die Apple-Klasse wie folgt:

class Apple: IApple, IDisposable
{ }

Verbraucher der IApple ist jetzt völlig unbeeindruckt von der Tatsache, dass Instanzen IDisposable ist. In diesem Fall werden wir die Behältergriff Entsorgung lassen.

So ist meine Schlussfolgerung ist, dass es als Entwickler von Apple ist für mich und IApple zu entscheiden, ob ich die Verbraucher Griff Entsorgung erfordern werden oder es verlassen, um einen Behälter auf.

Wenn Sie manchmal die Lebensdauer von Apple-Instanzen verwalten möchten sich selbst, und lassen manchmal den Behälter handle es, dann können Sie zwei Schnittstellen definieren:

public IApple
{
   void Consume();
}

public IDisposableApple : IApple, IDisposable
{
}

Und dann die Klasse registriert zweimal:

builder.RegisterType<Apple>().As<IApple>();
builder.RegisterType<Apple>().As<IDisosableApple>().ExternallyOwned(); 

Sie können dann inject ein DisposableAppleFactory in Klassen, die Notwendigkeit, zu erstellen und zu entsorgen Äpfel.

Für Klassen, die nur einen Apfel mit der gleichen Lebensdauer wie der Behälter benötigen, können Sie inject IApple statt.

Allerdings ist die Tatsache, dass Sie benötigen beide anzeigen, dass Sie mischen newables und injizierbare . Apple kann einfach ein „newable“ Objekt, das heißt eine, die nicht von den IoC-Containern verwaltet benötigt werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top