V4 V5

独自の関数を数式から呼べるように登録できます。組込関数と同じ仕組みの上に載るため、 依存再計算も参照シフトもそのまま働きます。

名前空間は unvell.ReoGrid.Core.Formula です。

登録する

using unvell.ReoGrid.Core;
using unvell.ReoGrid.Core.Formula;

// 引数が評価済みで渡される通常の関数
FunctionRegistry.Default.Eager("TAXINCL", (args, ctx) =>
{
	if (args.Length < 1) return FormulaValue.Err(FormulaError.NA);
	if (args[0].IsError) return args[0];        // エラーは伝播させる

	double rate = args.Length > 1 ? args[1].Num : 0.1;
	return FormulaValue.Number(args[0].Num * (1 + rate));
});

ws.SetFormula(0, 1, "TAXINCL(A1)");
ws.SetFormula(1, 1, "TAXINCL(A2, 0.08)");

関数名は大文字で登録してください。数式中の関数名は大文字に正規化されて照合されます。

登録は FunctionRegistry.Default に対して行うため、プロセス全体で共有されます。 アプリケーションの起動時に一度だけ行ってください。

FormulaValue

引数と戻り値の型です。

生成種別
FormulaValue.Number(v)数値
FormulaValue.Text(s)文字列
FormulaValue.Logical(b)真偽値
FormulaValue.Date(serial)日付(OLE シリアル値)
FormulaValue.Err(FormulaError.Value)エラー
判定・取り出し内容
IsError / IsNil / IsRange種別の判定
IsNumberLike数値・真偽値・日付のいずれか
Num数値としての値
Str文字列としての値
var n = FormulaValue.Number(42);
var t = FormulaValue.Text("hello");
var b = FormulaValue.Logical(true);
var d = FormulaValue.Date(DateTime.Today.ToOADate());
var e = FormulaValue.Err(FormulaError.Value);

範囲を受け取る

範囲は展開されずに渡されます。中身が必要な場合は評価コンテキストから読みます。

FunctionRegistry.Default.Eager("COUNTPOSITIVE", (args, ctx) =>
{
	int count = 0;

	foreach (var a in args)
	{
		if (a.IsError) return a;

		if (a.IsRange)
		{
			for (int r = a.R1; r <= a.R2; r++)
				for (int c = a.C1; c <= a.C2; c++)
				{
					var v = ctx.GetCell(r, c, a.RangeSheet);
					if (v.IsNumberLike && v.Num > 0) count++;
				}
		}
		else if (a.IsNumberLike && a.Num > 0) count++;
	}

	return FormulaValue.Number(count);
});

a.RangeSheet は他シートの範囲を指している場合にそのシート名を持ちます(同一シートなら null)。 ctx.GetCell(row, col, sheet) に渡してください。

守るべき規約

  1. エラーは伝播させる。 引数がエラーなら、それをそのまま返すのが既定の作法です
  2. 引数不足は #N/A、型不整合は #VALUE! を返す
  3. 例外を投げない。 数式の評価中に例外が出ると再計算全体が失敗します。 エラー値を返してください
  4. 副作用を持たない。 再計算のタイミングと回数は保証されません

遅延評価

Lazy で登録すると、評価済みの値ではなく引数の構文木が渡されます。 ROW / COLUMN / OFFSET のように参照そのものを扱う関数に使います。

FunctionRegistry.Default.Lazy("MYREF", (argNodes, ctx) => { ... });

通常の計算関数には Eager を使ってください。

登録内容を確認する

bool exists = FunctionRegistry.Default.Has("TAXINCL");
int total = FunctionRegistry.Default.Count;

foreach (string name in FunctionRegistry.Default.Names)
	Console.WriteLine(name);

保存との関係

カスタム関数を使った数式は、文字列としてそのまま保存されます。読み込み側で同じ関数が 登録されていなければ #NAME? になります。

XLSX として書き出した場合、Excel では当然その関数を解釈できません。 配布するファイルにカスタム関数を含めるかどうかは、用途に応じて判断してください。

次に読む

ページの内容は役に立ちましたか?