Passaggio di dati a PSCmdlet dal relativo ArgumentTransformationAttribute
-
27-10-2019 - |
Domanda
In generale, sto cercando di creare un PSCmdlet
che accetta un parametro di un tipo che implementa IDisposeable
e richiede l'eliminazione per evitare perdite di risorse.Vorrei anche accettare un string
per quel parametro e creare un'istanza di quel tipo, tuttavia se creo quell'oggetto da solo, allora devo eliminarlo prima di tornare da ProcessRecord
.
Sto usando un ArgumentTransformationAttribute
con il mio parametro per costruire il mio oggetto IDisposeable
da una stringa, ma non riesco a trovare alcun modo per passare i dati da quella classe al mio PSCmdlet
se ho creato l'oggetto o meno.Ad esempio:
[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());
}
}
La mia ipotesi migliore qui è di sottoclassare il mio MyDisposeableClass
solo per taggare che ha bisogno di uno smaltimento esplicito, ma sembra abbastanza complicato, e sebbene funzioni in questo caso, ovviamente non funzionerebbe se volessi trattare con una classe sigillata.
C'è un modo migliore per farlo?
Soluzione 2
Alla fine, utilizzo semplicemente parametri che accettano un tipo che racchiude MyDisposeable
.La mia preoccupazione iniziale nel fare questo era che l'uso di un tipo interno per un parametro avrebbe avuto un impatto sull'accessibilità delle funzioni.(Forse avrebbe un impatto negativo sulla documentazione, ma in un cmdlet la documentazione è interamente controllata da un file XML.)
Dopo alcuni test, non sembrano esserci problemi nell'utilizzo di una classe interna per un parametro e nel lasciare che la trasformazione accetti tipi pubblici.Quindi creo semplicemente una classe wrapper:
public class MyDisposeableWrapper
{
public MyDisposeable MyDisposeable
{
get;
set;
}
public bool NeedsDisposed
{
get;
set;
}
public MyDisposeableWrapper(MyDisposeable myDisposeable, bool needsDisposed)
{
MyDisposeable = myDisposeable;
NeedsDisposed = needsDisposed;
}
}
E lascia che il parametro prenda quello invece.Nell'attributo di trasformazione, imposta semplicemente NeedsDisposed
in base al fatto che il parametro abbia preso un MyDisposeable
o ne abbia costruito uno.ad esempio:
if(input is MyDisposeable)
{
return new MyDisposeableWrapper((MyDisposeable) input, false);
}
else
{
/* construct MyDisposeable from the input */
return new MyDisposeableWrapper(myDisposeable, true);
}
Altri suggerimenti
Invece di creare sottoclassi, puoi aggiungere una proprietà alla tua classe MyDisposable?
public class MyDisposable
{
...
public bool IsAttributeCreated { get; set; }
}
Quindi nel codice dell'attributo
/* We created a MyDisposeable, we *should* dispose it */
return new MyDisposeable(input.ToString()){IsAttributeCreated=true};
Finalmente nel tuo blocco finale
finally
{
/* Should only dispose MyDisposeable if we created it... */
if (MyDisposable.IsAttributeCreated)
MyDisposeable.Dispose();
}