Предотвращение переноса PowerShell типов значений в PSObjects

У меня есть .NET API, который использует много делегатов. В моем API есть несколько методов, похожих на следующие:

public static class MyClass
{
    public static void DoSomethingWithString(Func<object> myFunc)
    {
        string myStringValue = myFunc().ToString();
        Console.WriteLine(myStringValue);
    }

    public static void DoSomethingWithDouble(Func<object> myFunc)
    {
        object unparsedValue = myFunc();
        double parsedValue = Convert.ToDouble(unparsedValue);
        Console.WriteLine(parsedValue);
    }
}

Теперь в PowerShell у меня есть следующее:

[MyClass]::DoSomethingWithString({ "Hello" }); # No error here
[MyClass]::DoSomethingWithDouble({ 123.4 });   # InvalidCastException - can't convert a PSObject to double

Проблема в том, что мой скриптовый блок PowerShell возвращает PSObject вместо фактического двойного значения. Мой .NET API ничего не знает о PowerShell, и я не хочу добавлять ссылку на библиотеки DLL PowerShell только для того, чтобы добавить специальную обработку для этого конкретного сценария.

Есть ли способ заставить мои блоки сценариев возвращать фактические типы значений, а не PSObjects? Или есть способ, не зависящий от PowerShell, для моей библиотеки .NET для обработки PSObjects?


person Phil    schedule 27.12.2013    source источник
comment
Почему бы просто не получить строковое значение (используя .tostring()), а затем преобразовать его? Он не знает, как преобразовать PSObject, но знает, как преобразовать строку.   -  person mjolinor    schedule 27.12.2013
comment
@mjolinor Я определенно хотел бы избежать этого решения, но похоже, что это мой единственный вариант.   -  person Phil    schedule 27.12.2013


Ответы (1)


PowerShell будет оборачивать вещи в PSObject по своему усмотрению, нет простого способа избежать этого при принятии произвольных блоков скриптов. Проявив некоторую дисциплину, вы можете написать блоки сценариев, которые разворачивают PSObject, например, следующее может работать нормально:

[MyClass]::DoSomethingWithDouble({ (123.4).PSObject.BaseObject })

Если возможно, лучше, чтобы ваш API принимал делегата с более конкретным типом возвращаемого значения.

public static void DoSomethingWithDouble(Func<double> myFunc)

В этом случае PowerShell преобразует возвращаемое значение в тип, ожидаемый делегатом. Когда тип возвращаемого значения — PSObject, PowerShell знает, что PSObject тривиально преобразуется в объект, поэтому он не разворачивается, но если тип возвращаемого значения практически любой другой, PowerShell вынужден выполнить преобразование, распаковывая PSObject.

Для полноты другой вариант, если вы используете PowerShell V3, — использовать ключевое слово C# dynamic, например:

public static void DoSomethingWithDouble(Func<object> myFunc)
{
    dynamic unparsedValue = myFunc();
    double parsedValue = (double)(unparsedValue);
    Console.WriteLine(parsedValue);
}

Если unparsedValue является PSObject, PowerShell выполнит преобразование from в double во второй строке, даже если вы не ссылаетесь ни на какие сборки PowerShell в коде C#.

Обратите внимание, что последние два параметра могут не подходить вашему реальному API, но их стоит понять.

person Jason Shirk    schedule 27.12.2013