Frage

Im Allgemeinen versuche ich, einen PSCmdlet zu erstellen, der einen Parameter eines Typs verwendet, der IDisposeable implementiert und entsorgt werden muss, um ein Auslaufen von Ressourcen zu vermeiden.Ich möchte auch einen string für diesen Parameter akzeptieren und eine Instanz dieses Typs erstellen. Wenn ich dieses Objekt jedoch selbst erstelle, muss ich es entsorgen, bevor ich vom ProcessRecord zurückkehre.

Ich verwende einen ArgumentTransformationAttribute mit meinem Parameter, um mein IDisposeable-Objekt aus einer Zeichenfolge zu erstellen, aber ich kann keine Möglichkeit finden, Daten aus dieser Klasse an meinen PSCmdlet zu übergeben, ob ich das Objekt erstellt habe oder nicht.Zum Beispiel:

[Cmdlet("Get", "MyDisposeableName")]
public class GetMyDisposeableNameCommand : PSCmdlet
{
    [Parameter(Mandatory = true, Position = 0), MyDisposeableTransformation]
    public MyDisposeable MyDisposeable
    {
        get;
        set;
    }

    protected override void ProcessRecord()
    {
        try
        {
            WriteObject(MyDisposeable.Name);
        }
        finally
        {
            /* Should only dispose MyDisposeable if we created it... */
            MyDisposeable.Dispose();
        }
    }
}

class MyDisposeableTransformationAttribute : ArgumentTransformationAttribute
{
    public override Object Transform(EngineIntrinsics engineIntrinsics, Object input)
    {
        if (input is PSObject && ((PSObject)input).BaseObject is MyDisposeable)
        {
            /* We were passed a MyDisposeable, we should not dispose it */
            return ((PSObject)input).BaseObject;
        }

        /* We created a MyDisposeable, we *should* dispose it */
        return new MyDisposeable(input.ToString());
    }
}

Meine beste Vermutung hier ist, meinen MyDisposeableClass zu unterordnen, nur um zu kennzeichnen, dass er explizit entsorgt werden muss, aber das scheint ziemlich hackig zu sein, und obwohl es in diesem Fall funktioniert, würde es offensichtlich nicht funktionieren, wenn ich mich mit einer versiegelten Klasse befassen möchte.

Gibt es einen besseren Weg, dies zu tun?

War es hilfreich?

Lösung 2

Am Ende verwende ich einfach Parameter, die einen Typ akzeptieren, der MyDisposeable umschließt.Meine anfängliche Sorge dabei war, dass die Verwendung eines internen Typs für einen Parameter die Zugänglichkeit der Funktionen beeinträchtigen würde.(Möglicherweise würde sich dies negativ auf die Dokumentation auswirken, aber in einem Cmdlet wird die Dokumentation vollständig von einer XML-Datei gesteuert.)

Nach einigen Tests scheint es keine Probleme zu geben, eine interne Klasse für einen Parameter zu verwenden und die Transformation nur öffentliche Typen akzeptieren zu lassen.Also erstelle ich einfach eine Wrapper-Klasse:

public class MyDisposeableWrapper
{
    public MyDisposeable MyDisposeable
    {
        get;
        set;
    }

    public bool NeedsDisposed
    {
        get;
        set;
    }

    public MyDisposeableWrapper(MyDisposeable myDisposeable, bool needsDisposed)
    {
        MyDisposeable = myDisposeable;
        NeedsDisposed = needsDisposed;
    }
}

Und lassen Sie den Parameter das stattdessen nehmen.Legen Sie im Transformationsattribut einfach den NeedsDisposed fest, basierend darauf, ob der Parameter einen MyDisposeable verwendet oder einen erstellt hat.zB:

if(input is MyDisposeable)
{
    return new MyDisposeableWrapper((MyDisposeable) input, false);
}
else
{
    /* construct MyDisposeable from the input */
    return new MyDisposeableWrapper(myDisposeable, true);
}

Andere Tipps

Können Sie Ihrer MyDisposable-Klasse anstelle von Unterklassen eine Eigenschaft hinzufügen?

public class MyDisposable
{
    ...   
    public bool IsAttributeCreated { get; set; }
}

Dann in Ihrem Attributcode

/* We created a MyDisposeable, we *should* dispose it */
return new MyDisposeable(input.ToString()){IsAttributeCreated=true};

Endlich in Ihrem finally-Block

finally
{
    /* Should only dispose MyDisposeable if we created it... */
    if (MyDisposable.IsAttributeCreated)
        MyDisposeable.Dispose();
}

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