C#でPower Fxのカスタム関数を実装する方法

この記事は公開から2年以上経過しています。

.NET開発でPower Fxを利用する際、標準では提供されていない機能を自前で実装して関数として利用する方法を紹介します。

本例は.NET 6のコンソールアプリケーションですが、Power Fx自体はNET Framework(4.7.2以上)上のWinForms/WPFからでも利用可能です。

2022.9.9追記:
PowerFx 0.2.2-previewの変更に対応しました。
・アセンブリ名と外部I/F変更の変更。
・Randbetween組み込み関数追加に伴いサンプルの関数名をRandBetweenRandBetween2に変更。


サンプルソースコード(C#)

本例では指定された範囲内の整数の乱数を返すRandBetween2(minVal, maxVal)関数を作成します。
カスタム関数の実装方法についてのサンプルのため、入力チェックやエラー処理は行なっていません。

2022.1.6時点ではVisual StudioのNuGetパッケージマネージャー経由でPower Fxを導入する場合、パッケージ検索テキストボックス右のプレリリースを含めるにチェックを入れておく必要があります。

PowerFx 0.2.1-preview

PowerFx220106.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.PowerFx.Core" Version="0.2.1-preview" />
    <PackageReference Include="Microsoft.PowerFx.Interpreter" Version="0.2.1-preview" />
  </ItemGroup>

</Project>

Program.cs

using System;
using System.Globalization;
using Microsoft.PowerFx;
using Microsoft.PowerFx.Core.Public.Types;
using Microsoft.PowerFx.Core.Public.Values;

static class PowerFxTest210106
{
    public static void Main(string[] _)
    {
        // CurrentCultureがnullの場合の対策
        CultureInfo.CurrentCulture = new CultureInfo("ja-JP");

        // Power Fxエンジンの生成
        var engine = new RecalcEngine();
        // Randbetween関数を追加
        engine.AddFunction(new RandBetween2());

        // 追加したRandbetween関数を実行
        for (var i = 0; i < 10; ++i)
        {
            var ret = engine.Eval(@"RandBetween2(1, 100)");
            if (ret is NumberValue sb)
                Console.WriteLine(sb.Value);
        }
    }

    // RandBetween2(minVal, maxVal)
    private sealed class RandBetween2 : ReflectionFunction
    {
        // 乱数初期化(シードなし)
        private readonly Random _rand = new();

        // 戻り値、パラメータ1、パラメータ2は数値として初期化
        public RandBetween2() : base(nameof(RandBetween2), FormulaType.Number, FormulaType.Number, FormulaType.Number) { }

        // 戻り値、パラメータ1、パラメータ2は数値
        public NumberValue Execute(NumberValue numBegin, NumberValue numEnd)
        {
            return FormulaValue.New(_rand.Next((int)numBegin.Value, ((int)numEnd.Value) + 1));
        }
    }
}

PowerFx 0.2.2-preview以降

PowerFx220106.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.PowerFx.Core" Version="0.2.2-preview" />
    <PackageReference Include="Microsoft.PowerFx.Interpreter" Version="0.2.2-preview" />
  </ItemGroup>

</Project>

Program.cs

using System;
using System.Globalization;
using Microsoft.PowerFx;
using Microsoft.PowerFx.Types;

static class PowerFxTest220106
{
    public static void Main(string[] _)
    {
        // CurrentCultureがnullの場合の対策
        CultureInfo.CurrentCulture = new CultureInfo("ja-JP");

        // Power Fxコンフィグ作成
        var config = new PowerFxConfig();
        // Randbetween関数を追加
        config.AddFunction(new RandBetween2());

        // Power Fxエンジンの生成
        var engine = new RecalcEngine(config);

        // 追加したRandbetween関数を実行
        for (var i = 0; i < 10; ++i)
        {
            var ret = engine.Eval(@"RandBetween2(1, 100)");
            if (ret is NumberValue sb)
                Console.WriteLine(sb.Value);
        }
    }

    // RandBetween2(minVal, maxVal)
    private sealed class RandBetween2 : ReflectionFunction
    {
        // 乱数初期化(シードなし)
        private readonly Random _rand = new();

        // 戻り値、パラメータ1、パラメータ2は数値として初期化
        public RandBetween2() : base(nameof(RandBetween2), FormulaType.Number, FormulaType.Number, FormulaType.Number) { }

        // 戻り値、パラメータ1、パラメータ2は数値
        public NumberValue Execute(NumberValue numBegin, NumberValue numEnd)
        {
            return FormulaValue.New(_rand.Next((int)numBegin.Value, ((int)numEnd.Value) + 1));
        }
    }
}


出力結果

プログラムを実行すると、今回作成したカスタム関数RandBetween2(1, 100)をループで10
回評価することで、1〜100までの整数の乱数値を10個表示します。

40
63
93
66
55
68
5
70
93
91


参考ウェブサイトなど

以上です。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする