【问题标题】:GetDynamicParameters() not invoked when another parameter is specified指定另一个参数时未调用 GetDynamicParameters()
【发布时间】:2016-01-03 23:05:57
【问题描述】:

我正在 C# 中开发一个 PowerShell cmdlet Get-Foo,它定义了一个 dynamic parameter Bar,只有在指定开关参数 MySwitch 时才会显示。它还有其他参数MyStringMyIntMyBool

当我运行 cmdlet 时,当我指定开关参数 MySwitch 以及 MyStringMyInt 时,动态参数 Bar 会很好地显示在选项卡完成中,但当我将它与 @987654332 一起使用时不会@(或任何其他参数类型)。

代码如下:

namespace MyCompany.Cmdlets
{
    [Cmdlet(VerbsCommon.Get, "Foo")]
    public class GetFoo : PSCmdlet, IDynamicParameters
    {
        [Parameter]
        public string MyString { get; set; }

        [Parameter]
        public int MyInt { get; set; }

        [Parameter]
        public bool MyBool { get; set; }

        [Parameter]
        public SwitchParameter MySwitch { get; set; }

        public object GetDynamicParameters()
        {
            if (MySwitch.IsPresent)
            {
                context = new FooParameters();
                return context;
            }

            return null;
        }

        private FooParameters context;

        protected override void ProcessRecord() {}
    }

    public class FooParameters
    {
        [Parameter]
        public string Bar { get; set; }
    }
}

我做错了什么?指定MyBool 参数(或MyObject 参数)时如何显示动态参数?

【问题讨论】:

  • 只是出于好奇:为什么要将位置分配给开关参数?这种类型几乎没有任何意义 - 它(本质上)是命名参数......不确定这是否会导致动态参数出现问题,但我不会感到惊讶。
  • 我认为,PowerShell 无法伪造 bool 参数的绑定值。它在完成解析时不评估表达式。例如,如果你写-MyString $a,而不是GetDynamicParameters,它将被视为$a,而不是变量的值。因此,PowerShell 可能无法将字符串 $false$true 转换为 bool 值。
  • @BartekB 这只是我为了让它发挥作用而玩弄的事情之一。即使我删除了所有位置属性,它也不起作用。

标签: c# powershell dynamic parameters cmdlets


【解决方案1】:

当使用结构体“SwitchParameter”时,我将其视为处理任何其他布尔值,例如:

if (MySwitchParameter)
{ 
   // la la la other stuff
}

GetDynamicParameters 很棘手,但是,就 Return 而言,您有两个选择 值:返回一个代表您的参数的对象 OR 返回一个 RuntimeDefinedParameterDictionary 对象。想想 RuntimeDefinedParameterDictionary 作为表达参数的“CodeDom-Like”方式。

这里可能会重写您的 Get-Foo Cmdlet,重点是动态参数:

[Cmdlet(VerbsCommon.Get, "Foo",
    SupportsShouldProcess = true
    )]
public class GetFooCommand : PSCmdlet, IDynamicParameters
{
    // First things first: Lets try making a dictionary for our return 
    // value in our implementation of IDynamicParameter's 
    // GetDynamicParameters() method
    private RuntimeDefinedParameterDictionary DynamicParameters;

    [Parameter]
    public string MyString { get; set; }

    [Parameter]
    public int MyInt { get; set; }

    [Parameter]
    // Booleans are not as fun as SwitchParameters, IMHO
    public bool MyBool { get; set; }


    // Remember that SwitchParameter is really just a boolean (sort of), so 
    // it will default to 'false'
    [Parameter]
    public SwitchParameter MySwitch { get; set; }

    public object GetDynamicParameters()
    {
        // You only want this to run when the switch is flipped,
        // so try it this way and see if it works for you
        if (MySwitch)
        {
            // Create the dictionary. We will return this at the end because
            // **** spoiler alert **** it is an object :)
            var runtimeParameterDictionary = new RuntimeDefinedParameterDictionary();


            // Lets make that parameter now. Your example doesn't specify any 
            // additional parameter attributes beyond the required "ParameterAttribute", 
            // so here we create an empty Attribute Collection
            var runtimeParameter = 
            new RuntimeDefinedParameter("Bar", typeof (string), new Collection<Attribute>());

            // With a new Parameter, lets add it to our dictionary. 
            runtimeParameterDictionary.Add("Bar", runtimeParameter);

            // Because we created a field for our dictionary way up top, we can assign it like I
            // illustrate below. This will enable easy, predictable results when we seek to 
            // extract the values from the dictionary at runtime.
            DynamicParameters = runtimeParameterDictionary;


            // Note: You can add as many parameters as you want this way, and that Is 
            // why I recommend it to you now. Coding the parameters as classes outside of the 
            // Cmdlet, and to some extent as embedded Classes,
            // within the Cmdlet Never really worked for me, so I feel your pain/frustration.

            return runtimeParameterDictionary;
        }

        return null; // Guess the user doesn't want that Bar afterall;
    }

    protected override void ProcessRecord()
    {
        // We obviously want to sequester everything we are doing with the dynamic
        // parameters so a good-old-fashioned if.. then.. else... will suffice.
        if (MySwitch)
        {
            // Now we are here at the precipice of this DynamicParameter cmdlet.
            // Here is one way to get the value desired from the dynamic parameter.

            // Simply access it like a dictionary...
            var bar = DynamicParameters["Bar"].Value as string;

            // The reason we can do it this way is because we assigned our
            // beloved value to the local variable "DynmaicParameters"
            // in the GetDynamicParameters() method. We could care less about 
            // the return value, because if the 
            // switch is flipped, "DynamicParameters" will be our new best friend, and
            // it will have everything we need.

            WriteWarning("Your " + bar + " has been forwarded to an automatic voice messaging system ...");
        }


        WriteObject("Cheers was filmed before a live studio audience...");
        WriteObject(MyInvocation.BoundParameters);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    • 2012-07-12
    • 1970-01-01
    • 2017-01-22
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多