将数据从 ArgumentTransformationAttribute 传递到 PSCmdlet

发布于 2025-01-07 06:47:32 字数 1537 浏览 1 评论 0原文

一般来说,我尝试创建一个 PSCmdlet,它采用实现 IDisposeable 的类型的参数,并需要进行处置以避免泄漏资源。我还想接受该参数的字符串并创建该类型的实例,但是如果我自己创建该对象,那么我需要在从 ProcessRecord 返回之前处理它>。

我将 ArgumentTransformationAttribute 与我的参数一起使用,以便从字符串构造我的 IDisposeable 对象,但我找不到任何方法将数据从该类传递到我的 PSCmdlet 关于我是否创建了该对象。例如:

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

我最好的猜测是对我的 MyDisposeableClass 进行子类化,只是为了标记它需要显式处置,但这看起来相当老套,虽然它在这种情况下有效,但如果我想要处理一个密封类。

有更好的方法吗?

Generally, I'm trying to create a PSCmdlet that takes a parameter of a type that implements IDisposeable and requires disposal in order to avoid leaking resources. I would also like to accept a string for that parameter and create an instance of that type, however if I create that object myself, then I need to dispose it before returning from ProcessRecord.

I'm using an ArgumentTransformationAttribute with my parameter in order to construct my IDisposeable object from a string, but I cannot find any way to pass data from that class to my PSCmdlet about whether I created the object or not. For example:

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

My best guess here is to subclass my MyDisposeableClass just to tag that it needs explicit disposal, but that seems fairly hacky, and while it works in this case, it obviously wouldn't work if I wanted to deal with a sealed class.

Is there a better way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

摇划花蜜的午后 2025-01-14 06:47:32

您是否可以向 MyDisposable 类添加一个属性,而不是子类化?

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

然后在你的属性代码中

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

最后在你的finally块中

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

Rather than subclassing, can you add a property to your MyDisposable class?

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

Then in your attribute code

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

Finally in your finally block

finally
{
    /* Should only dispose MyDisposeable if we created it... */
    if (MyDisposable.IsAttributeCreated)
        MyDisposeable.Dispose();
}
喜爱皱眉﹌ 2025-01-14 06:47:32

最后,我只是使用接受包装 MyDisposeable 类型的参数。我最初担心这样做是使用内部类型作为参数会影响函数的可访问性。 (也许这会对文档产生负面影响,但在 cmdlet 中,文档完全由 XML 文件控制。)

经过一些测试,使用内部类作为参数并让转换接受公共类型似乎没有任何问题。所以我只是创建一个包装类:

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

    public bool NeedsDisposed
    {
        get;
        set;
    }

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

并让参数采用它。在转换属性中,只需根据参数是采用 MyDisposeable 还是构造参数来设置 NeedsDispose 即可。例如:

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

In the end, I simply use parameters that accept a type that wraps MyDisposeable. My initial concern with doing this was that using an internal type for a parameter would impact the functions accessibility. (Perhaps it would negatively impact documentation, but in a cmdlet the documentation is wholly controlled by an XML file.)

After some testing, there do not appear to be any problems using an internal class for a parameter and just letting the transformation accept public types. So I simply create a wrapper class:

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

    public bool NeedsDisposed
    {
        get;
        set;
    }

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

And have the parameter take that instead. In the transformation attribute, simply set NeedsDisposed based on whether the parameter took a MyDisposeable or constructed one. eg:

if(input is MyDisposeable)
{
    return new MyDisposeableWrapper((MyDisposeable) input, false);
}
else
{
    /* construct MyDisposeable from the input */
    return new MyDisposeableWrapper(myDisposeable, true);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文