Pregunta

Generalmente, estoy tratando de crear un PSCmdlet que toma un parámetro de un tipo que implementa IDisposeable y requiere eliminación para evitar fugas de recursos.También me gustaría aceptar un string para ese parámetro y creo una instancia de ese tipo, sin embargo, si creo ese objeto yo mismo, entonces necesito desecharlo antes de regresar de ProcessRecord.

estoy usando un ArgumentTransformationAttribute con mi parámetro para construir mi IDisposeable objeto de una cadena, pero no puedo encontrar ninguna manera de pasar datos de esa clase a mi PSCmdlet sobre si creé el objeto o no.Por ejemplo:

[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());
    }
}

Mi mejor suposición aquí es subclasificar mi MyDisposeableClass solo para etiquetar que necesita eliminación explícita, pero eso parece bastante complicado, y si bien funciona en este caso, obviamente no funcionaría si quisiera tratar con una clase sellada.

¿Hay una mejor manera de hacer esto?

¿Fue útil?

Solución 2

Al final, simplemente uso parámetros que aceptan un tipo que envuelve MyDisposeable.Mi preocupación inicial al hacer esto fue que el uso de un tipo interno para un parámetro afectaría la accesibilidad de las funciones.(Quizás afectaría negativamente a la documentación, pero en un cmdlet la documentación está totalmente controlada por un archivo XML).

Después de algunas pruebas, no parece haber ningún problema al usar una clase interna como parámetro y simplemente dejar que la transformación acepte tipos públicos.Entonces simplemente creo una clase contenedora:

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

    public bool NeedsDisposed
    {
        get;
        set;
    }

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

Y haga que el parámetro tome eso en su lugar.En el atributo de transformación, simplemente establezca NeedsDisposed basado en si el parámetro tomó un MyDisposeable o construido.p.ej:

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

Otros consejos

En lugar de crear subclases, ¿puedes agregar una propiedad a tu clase MyDisposable?

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

Luego en tu código de atributo

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

Finalmente en tu bloque finalmente

finally
{
    /* Should only dispose MyDisposeable if we created it... */
    if (MyDisposable.IsAttributeCreated)
        MyDisposeable.Dispose();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top