Table of Contents

如何检查对象类型

TOM 层级结构采用继承机制。 Column 是一个抽象基类,其子类型包括 DataColumnCalculatedColumnCalculatedTableColumnTable 的子类型包括 CalculatedTableCalculationGroupTable。 在处理 NameDescriptionIsHiddenFormatStringDisplayFolder 等共享属性时,请使用基类型。 当需要特定类型的属性时,请将其强制转换为具体子类型,例如 CalculatedColumnExpressionDataColumnSourceColumn

快速参考

// Pattern matching -- checks type AND casts in one step
if (col is CalculatedColumn cc)
    Info(cc.Expression);  // Expression is only on CalculatedColumn, not base Column

// Filter a collection by type
var calcCols = Model.AllColumns.OfType<CalculatedColumn>();
var calcGroups = Model.Tables.OfType<CalculationGroupTable>();

// Runtime type name (use only for display/logging, not for logic)
var typeName = obj.GetType().Name;   // "DataColumn", "Measure", etc.
Note

在 Tabular Editor 2 中,带变量声明的模式匹配(col is CalculatedColumn cc)需要 Roslyn 编译器。 在 File > 偏好 > General > Compiler path 下进行配置。 详情请参阅 使用 Roslyn 编译。 Tabular Editor 3 默认支持此功能。

类型层次结构

TOMWrapper 中的关键继承关系如下:

基类型 子类型
(xref:TabularEditor.TOMWrapper.Column) (xref:TabularEditor.TOMWrapper.DataColumn), (xref:TabularEditor.TOMWrapper.CalculatedColumn), (xref:TabularEditor.TOMWrapper.CalculatedTableColumn)
(xref:TabularEditor.TOMWrapper.Table) (xref:TabularEditor.TOMWrapper.CalculatedTable), (xref:TabularEditor.TOMWrapper.CalculationGroupTable)
分区 (xref:TabularEditor.TOMWrapper.Partition) 分区子类型:(xref:TabularEditor.TOMWrapper.MPartition), (xref:TabularEditor.TOMWrapper.EntityPartition), (xref:TabularEditor.TOMWrapper.PolicyRangePartition)
(xref:TabularEditor.TOMWrapper.DataSource) (xref:TabularEditor.TOMWrapper.ProviderDataSource), (xref:TabularEditor.TOMWrapper.StructuredDataSource)

按类型筛选集合

OfType<T>() 可用于任何集合,并返回一个经过筛选的序列,其中只包含指定类型的项。 如果没有匹配项,它会返回空序列。

// All calculated columns in the model (empty if model has none)
var calculatedColumns = Model.AllColumns.OfType<CalculatedColumn>();

// All M partitions (Power Query)
var mPartitions = Model.AllPartitions.OfType<MPartition>();

// All calculation group tables
var calcGroups = Model.Tables.OfType<CalculationGroupTable>();

// All regular tables (exclude calculation groups and calculated tables)
var regularTables = Model.Tables.Where(t => t is not CalculationGroupTable && t is not CalculatedTable);

使用 is 进行模式匹配

模式匹配会做两件事:检查某个值是否为给定类型,并可选择将其转换后赋给一个新变量。 x is Type xx 这种形式会判断“x 是否为 Type 类型?”,如果为真,就会将 xx 作为该确切类型的变量供你使用。

这等同于:

if (col is CalculatedColumn)
{
    var cc = (CalculatedColumn)col; // explicit cast
    // use cc...
}

如果你只需要布尔判断,使用不带变量的 x is Type。 如果你还需要访问子类型特有的属性,用 x is Type xx

foreach (var col in Model.AllColumns)
{
    // Expression is only available on CalculatedColumn, not the base Column type
    if (col is CalculatedColumn cc)
        Info($"{cc.Name}: {cc.Expression}");
    else if (col is DataColumn dc)
        Info($"{dc.Name}: data column in {dc.Table.Name}");
}

Dynamic LINQ 中的等效写法

在 BPA 规则中,类型筛选是通过规则的 Applies to 范围来处理的。 把它设置为目标对象类型(例如 计算列),不要在表达式中按类型筛选。 Dynamic LINQ 不支持 C# 风格的类型转换。

常见陷阱

Important
  • Column 是抽象类型,但你无需进行类型转换,也可以访问基类型上定义的所有属性(NameDataTypeFormatStringIsHiddenDescriptionDisplayFolder)。 只有在你需要子类型特有的属性(例如 CalculatedColumn 上的 Expression)时,才将其转换为该子类型。
  • OfType<T>() 会同时进行筛选和类型转换。 Where(x => x is T) 只会筛选,结果仍然是基类型。 当你需要访问子类型属性时,优先使用 OfType<T>()
  • 计算表格的列会自动管理。 要添加或更改列,就编辑计算表格的 Expression。 你不能直接添加这些列。

另见