SharpCell

Formulas and values

How to write formulas, what a cell value can be, and how dynamic arrays, names and LAMBDA work.

Syntax

Write formulas the way Excel stores them in a file: English function names, a comma between arguments and a dot as the decimal separator. The leading = is optional; Cell.Formula adds it if missing. Localized function names such as СУММ or SOMME are not recognized.

References:

Form Meaning
A1, $A$1 A cell, relative or absolute
A1:C3, A:A, 1:1 A range, whole columns, whole rows
'Sheet name'!A1 A cell on another sheet
Sheet1:Sheet3!A1 The same cell on a run of sheets
TaxRate A defined name
C1# The whole range a dynamic array in C1 spilled into
@A1:A9 Implicit intersection: the cell of the range in the formula's row or column

Build a workbook in code

var workbook = new Workbook();
Worksheet sheet = workbook.AddSheet("Sheet1");
sheet["A1"].Value = 2;
sheet["A2"].Formula = "=A1*3";
workbook.Recalculate();
CellValue result = sheet["A2"].Value;   // 6

Reading values

A CellValue is one of: Number, Text, Boolean, Error, Array, Empty, Missing or Lambda. Dates and times are numbers: serial days since the workbook's date system epoch. Errors such as #DIV/0! are values, not exceptions.

static string Describe(CellValue value) => value.Kind switch
{
    CellValueKind.Number => value.AsNumber().ToString(CultureInfo.InvariantCulture),
    CellValueKind.Text => value.AsText(),
    CellValueKind.Boolean => value.AsBoolean() ? "TRUE" : "FALSE",
    CellValueKind.Error => value.AsError().ToText(),   // "#DIV/0!", "#N/A", ...
    CellValueKind.Array => $"array of {value.AsArray().GetLength(0)} x {value.AsArray().GetLength(1)}",
    CellValueKind.Empty => "(empty)",
    _ => value.ToString(),
};

The As methods throw InvalidOperationException when the value is of another kind. Every member is listed in the CellValue reference.

Dynamic arrays

A formula that returns several values spills into the cells below and to the right. The spilled cells hold values but no formula: their Formula is null.

sheet["C1"].Formula = "=SEQUENCE(3)";   // spills into C1:C3
sheet["D1"].Formula = "=SUM(C1#)";      // C1# is the whole spilled range
workbook.Recalculate();
// sheet["C3"].Value is 3 and sheet["D1"].Value is 6

When a cell in the way holds something, the anchor shows #SPILL! and the other cells stay as they are:

sheet["C2"].Value = "in the way";
workbook.Recalculate();
// sheet["C1"].Value is #SPILL!; clear C2 and recalculate to spill again

Names and LAMBDA

DefineName gives a formula a name. A name whose formula is a LAMBDA can be called like a function.

workbook.DefineName("TaxRate", "=0.2");
workbook.DefineName("WithTax", "=LAMBDA(amount, amount * (1 + TaxRate))");
CellValue gross = workbook.Evaluate("=WithTax(100)");   // 120

A function's name alone is the function as a value, wherever a LAMBDA is expected: in MAP, REDUCE, SCAN, BYROW, BYCOL, MAKEARRAY and as the value of a LET name. It takes its arguments as a call by name would. Custom functions can be passed the same way.

sheet["D1"].Formula = "=BYROW(A1:B2, SUM)";            // 3 and 7: SUM is passed as a function
sheet["E1"].Formula = "=LET(size, LEN, size(\"abc\"))";  // 3
workbook.Recalculate();

Formulas outside cells

CellValue sum = workbook.Evaluate("=SUM(1, 2, 3)");   // 6, no sheet needed

Errors in formula text

Text that is not a valid formula throws FormulaParseException, which says where parsing stopped. The cell is left unchanged.

string? problem = null;
try
{
    sheet["A1"].Formula = "=SUM(1,";
}
catch (FormulaParseException e)
{
    problem = $"at position {e.Position}: {e.Message}";
}

A formula read from a file that SharpCell cannot handle does not throw. Once calculated, it is #NAME? and listed in Workbook.Diagnostics as UnsupportedFormula. See Reading .xlsx files.