Pergunta

Geralmente, estou tentando criar um PSCmdlet que usa um parâmetro de um tipo que implementa IDisposeable e requer descarte para evitar o vazamento de recursos.Também gostaria de aceitar um string para esse parâmetro e criar uma instância desse tipo; no entanto, se eu mesmo criar esse objeto, preciso descartá-lo antes de retornar de ProcessRecord.

Estou usando um ArgumentTransformationAttribute com meu parâmetro para construir meu objeto IDisposeable a partir de uma string, mas não consigo encontrar nenhuma maneira de passar dados dessa classe para meu PSCmdlet sobre se criei o objeto ou não.Por exemplo:

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

Meu melhor palpite aqui é subclassificar meu MyDisposeableClass apenas para marcar que ele precisa de descarte explícito, mas isso parece bastante hacky e, embora funcione neste caso, obviamente não funcionaria se eu quisesse lidar com uma classe selada.

Existe uma maneira melhor de fazer isso?

Foi útil?

Solução 2

No final, eu simplesmente uso parâmetros que aceitam um tipo que envolve MyDisposeable.Minha preocupação inicial em fazer isso era que usar um tipo interno para um parâmetro impactaria a acessibilidade das funções.(Talvez isso tenha um impacto negativo na documentação, mas em um cmdlet a documentação é totalmente controlada por um arquivo XML.)

Após alguns testes, não parece haver nenhum problema em usar uma classe interna para um parâmetro e apenas permitir que a transformação aceite tipos públicos.Então, simplesmente crio uma classe de 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 faça com que o parâmetro use isso.No atributo de transformação, basta definir NeedsDisposed com base em se o parâmetro recebeu um MyDisposeable ou construiu um.por exemplo:

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

Outras dicas

Em vez de criar subclasses, você pode adicionar uma propriedade à sua classe MyDisposable?

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

Então, em seu código de atributo

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

Finalmente em seu bloco final

finally
{
    /* Should only dispose MyDisposeable if we created it... */
    if (MyDisposable.IsAttributeCreated)
        MyDisposeable.Dispose();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top