PowerShellExpression クラスの実装

先日はPowerShellによる式評価が簡単にC#から呼び出せることが判ったので、次の段階として実際にDIコンテナに組み込んでみることにした。と書くと大袈裟になりそうな感じがするが、元々Sesar2等と同様の評価式インタフェースは実装が既に済んでいるので、それを拡張するクラスの実装は非常に簡単だ。

  • IExpressionインタフェース

式評価のためのインタフェースは単純だ。評価を行うためのEvaluateメソッドと、評価に使用する式にアクセスするExpresionStringプロパティが定義される。

public interface IExpression {
    object Evaluate(IDIContainer container);
    string ExpresionString { get; set; }
}
  • PowerShellExpressionクラスを実装する

あとは、IExpressionインタフェースを実装するだけだ。インタフェースをそのまま実装しても良いのだが、既に.NETにおける式評価のための基本的な実装のテンプレートである、AbstractDotnetExpressionクラスが存在している。

public abstract class AbstractDotnetExpression : IExpression {
    private string expression;

    public AbstractDotnetExpression(string expression) {
        this.expression = expression;
    }
    public string ExpresionString  { 
        get { return this.expression; }
        set { this.expression = value; } 
    }
    public object Evaluate(IDIContainer container) {
        〜 .NETに特有な型コンバータが取得できる場合は変換を行う
        〜 略
        return this.DoEvaluate(container);
    }
    protected abstract object DoEvaluate(IDIContainer container);
}

従って、この抽象クラスから継承したPowerShellExpressionを用意して、DoEvaluateメソッドをオーバライドするだけである。

public class PowerShellExpression : AbstractDotnetExpression {
    private static readonly RunspaceInvoke invoker = new RunspaceInvoke();

    public PowerShellExpression(string expression)
        : base(expression)
    {}
    protected override object DoEvaluate(IDIContainer container) {
        lock (invoker) {
            Collection result = invoker.Invoke(this.expression);
            return result[0].BaseObject;
        }
    }
}

PowerShellスクリプトを実行、評価するためのクラスであるRunspaceInvokeクラスはとりあえずスタティックなフィールドとして、インスタンス毎には生成しないようにしている。これはまだこのクラス、ひいてはPowerShellによるスクリプトが同時に実行される場合の特徴や制限などが全く不明なためだ。
式評価はたった一行のメソッド

Collection result = invoker.Invoke(this.expression);

で行われる。
とりあえず動けば良いだけの実装だが、このクラスを以下のような設定ファイルのパース時に生成することで、式評価によるインジェクションが可能になる。

<property name="Date">[DateTime]::now</property>
<property name="Size">new-object System.Drawing.Size(100, 100)</property>

目下の問題は、Invokeメソッドで戻ったPSObjectクラスのコレクションに、一体どのような結果が返ってくる可能性があるか、現時点では調べていないために全く解らないことだ。現状で判明しているのはスクリプト式の実行が成功した際には、コレクションの序数0の要素に実行結果の戻り値がセットされている、という事実だけである。なさけない話だ。