Tekla Structures Object API 完全解析
Tekla.Structures.Model.Object 是 Tekla Structures Open API 中绝对根抽象基类。一切模型对象——从 Beam、BoltArray、Weld 到 Assembly——都直接或间接地继承自这个仅有 37 行代码的抽象类。它定义了所有 Tekla 对象的共通身份:Identifier 属性及其与 C++ 内核的序列化桥梁。
本文基于 Tekla.Structures.Model 程序集(Version=2017.0.0.0)的反编译源码,深入解析 Object 类的完整定义、Identifier 生命周期、COM 互操作机制以及它在整个 Tekla API 体系中的根基地位。
一、继承体系
Object 是 Tekla 模型对象层级树的绝对根节点。它直接继承自 System.Object,声明为 public abstract class Object,意味着任何外部的 Tekla 对象都必定继承自此基类:
└── Object (abstract)
└── ModelObject (abstract)
├── Part (abstract) → Beam, ContourPlate, PolyBeam, Brep, BentPlate...
├── BaseComponent (abstract) → Connection, Component, Detail, CustomPart...
├── Assembly
├── Brep
├── ReferenceModel
└── ... 共 61 种派生类型
[图 1] Object 继承体系全景图 — 以 Object 为绝对根的全部派生类
Object 类标记了三个关键特性(Attribute):
| 特性 | 说明 |
|---|---|
| [ClassInterface(ClassInterfaceType.AutoDual)] | COM 互操作:自动为托管类生成 COM 接口,支持早期绑定(vtable)和后期绑定(IDispatch) |
| [Guid("4668C67A-...")] | COM 唯一标识符:为类在 COM 注册表中分配全局唯一 ID(CLSID) |
| [Serializable] | 序列化支持:标记该类及其所有派生类均可被 .NET 二进制序列化 |
Object 类的核心使命——作为 .NET 托管代码与 Tekla C++ 非托管内核之间的 互操作桥梁。[ClassInterface(AutoDual)] 使得 C++ 可以通过 COM 调用 .NET 对象;[Serializable] 确保对象状态可以在进程间传递。二、构造函数
Object 的构造函数声明为 protected,这意味着外部代码不能直接实例化 Object。只有派生类可以调用此构造函数来初始化 Identifier 属性。
// Object.cs 构造函数源码protectedObject(){this.Identifier=newIdentifier();}
构造函数执行以下关键初始化:
| 操作 | 说明 |
|---|---|
new Identifier() |
创建一个默认的 Identifier 实例,此时 ID = 0(无效状态) |
this.Identifier = ... |
将标识符赋值给当前对象,完成身份准备 |
| 继承链触发 | 当具体子类(如 Beam)通过 new Beam() 创建时,会自动触发 Object() → ModelObject() → Beam() 构造链 |
Identifier.ID = 0(无效)。这意味着对象仅存在于 .NET 内存中,尚未与 Tekla 模型数据库建立任何关联。只有调用 Insert() 或 Select()(由子类实现)后,Identifier 才会获得有效值。三、属性
Object 仅定义了一个公开属性——Identifier。这是整个 Tekla API 中最核心、最基础的属性。
Identifier 属性
| 属性名 | 类型 | 可读写 | 说明 |
|---|---|---|---|
| Identifier | Identifier |
读 / 写 | 模型对象的唯一标识符。ID=0 表示无效(未关联数据库);ID>0 表示有效 |
Identifier 生命周期
[图 2] Identifier 完整生命周期:从创建到回收
Identifier 的生命周期贯穿整个 Tekla 二次开发流程:
| 阶段 | 状态 | 说明 |
|---|---|---|
new Beam() |
ID = 0(无效) |
子类构造函数触发 protected Object(),创建默认 Identifier |
MatchIdentifier() |
ID = 哈希值 |
通过 Model.GetModelObjectSelector() 遍历时自动匹配,产生有效 ID |
Insert() |
ID > 0(有效) |
首次写入数据库后获得系统分配的正整数 ID |
Select() 成功 |
ID > 0(有效) |
已知 ID 选择已有对象,填充属性数据 |
Modify() |
ID > 0(有效) |
修改已存在对象,ID 不变 |
Delete() |
ID = 0(无效) |
删除后 ID 被置零(见 DeleteInstance() 源码),对象引用失效 |
Identifier 源码结构
// Identifier 核心结构publicstructIdentifier{publiclongID{get;set;}// 对象唯一标识 (0=无效, >0=有效)publicboolIsValid()// 判断 ID 是否有效{returnthis.ID>0L;}}
四、枚举类型
Object 类本身未定义任何枚举类型。作为绝对根基类,它的设计极为精简,仅提供基础设施(Identifier 属性 + 序列化桥接),将类型的枚举和分类职责交给了派生类——ModelObject.ModelObjectEnum 定义了 61 种模型对象枚举值。
Object 遵循"最小接口"原则。它只包含所有 Tekla 对象必然共同需要的部分:一个身份(Identifier)和一个序列化通道。任何更多的东西(如类型枚举、CRUD 操作、属性系统)都留给子类按需添加。五、方法
Object 类的所有方法均为 internal 访问级别,不暴露给外部二次开发代码。它们构成了 .NET 与 Tekla C++ 内核之间的序列化通道。
自身方法
| 方法 | 访问级别 | 返回类型 | 说明 |
|---|---|---|---|
ToStruct(ref dotObject_t) |
internal |
void |
将当前 Object 序列化为互操作结构体 dotObject_t |
FromStruct(ref dotObject_t) |
internal |
void |
从互操作结构体 dotObject_t 反序列化回 Object |
Object() |
protected |
构造函数 | 初始化 Identifier = new Identifier() |
序列化详细机制
[图 3] Object 序列化架构:从用户代码到 C++ 内核的四层数据流
序列化是 Object 类最核心的功能。整个数据流分为四层:
ToStruct — 托管→非托管序列化
// 将 .NET Object 导出为 C++ 结构体internalvoidToStruct(refdotObject_tdotObject){dotObject.Identifier=newdotIdentifier_t(this.Identifier);}
该方法将 .NET Identifier 转换为 COM 互操作结构体 dotIdentifier_t,存入 dotObject_t 的 Identifier 字段。这个转换是单向的——从托管类型到非托管类型,用于将数据传入 C++ 内核。
FromStruct — 非托管→托管反序列化
// 从 C++ 结构体恢复 .NET ObjectinternalvoidFromStruct(refdotObject_tdotObject){this.Identifier=dotObject.Identifier.FromStruct();}
该方法从传入的 dotObject_t 中提取 Identifier 字段,调用 dotIdentifier_t.FromStruct() 将其转换为 .NET Identifier 并回填到当前对象。这个反向转换用于从 C++ 内核读取数据到 .NET 层。
dotObject_t 互操作结构体
// 内部结构体 — Object 的 C++ 对应物publicstructdotObject_t{publicdotIdentifier_tIdentifier;// 仅包含一个字段}
dotObject_t 是非常简洁的结构体——只包含一个 dotIdentifier_t Identifier 字段。这体现了 Object 的极简设计:在 C++ 层,一个 Tekla 对象的本质就是一个标识符。所有扩展属性(如 Beam 的 StartPoint、Profile 等)都由子类的 dotXxx_t 结构体承载。
[图 4] Object 类成员全景:1 属性 + 2 方法 + 3 特性
六、完整代码示例
虽然 Object 是抽象类不能直接使用,但了解其工作原理对于深入理解 Tekla API 至关重要。以下是展示 Object 核心概念的实际代码示例。
示例 1:Identifier 生命周期追踪
usingSystem;usingTekla.Structures.Model;usingTekla.Structures.Geometry3d;publicvoidTraceIdentifierLifecycle(){// ===== 阶段 1:构造 (ID = 0,无效) =====BeammyBeam=newBeam();Console.WriteLine($"1. After new Beam(): ID={myBeam.Identifier.ID}, "+$"Valid={myBeam.Identifier.IsValid()}");// 输出: ID=0, Valid=False// 此时仅存在于 .NET 内存,未关联 Tekla 模型// ===== 阶段 2:设置属性 =====myBeam.StartPoint=newPoint(0,0,0);myBeam.EndPoint=newPoint(0,0,3000);myBeam.Profile.ProfileString="HEA200";myBeam.Material.MaterialString="S235JR";myBeam.Class="2";Console.WriteLine($"2. After property setup: ID={myBeam.Identifier.ID}");// 输出: ID=0 (属性设置不改变 ID)// ===== 阶段 3:插入数据库 =====boolinsertOk=myBeam.Insert();Console.WriteLine($"3. After Insert(): ID={myBeam.Identifier.ID}, "+$"Valid={myBeam.Identifier.IsValid()}, Result={insertOk}");// 输出: ID=12345 (系统分配), Valid=True, Result=True// ===== 阶段 4:通过 Select 获取已有对象 =====BeamselectedBeam=newBeam();selectedBeam.Identifier=newIdentifier(myBeam.Identifier.ID);boolselectOk=selectedBeam.Select();Console.WriteLine($"4. After Select({myBeam.Identifier.ID}): "+$"Valid={selectedBeam.Identifier.IsValid()}, Result={selectOk}");// 输出: Valid=True, Result=True// 从数据库加载了完整属性数据// ===== 阶段 5:修改 =====selectedBeam.Class="3";boolmodifyOk=selectedBeam.Modify();Console.WriteLine($"5. After Modify(): ID={selectedBeam.Identifier.ID}, "+$"Result={modifyOk}");// 输出: ID=12345 (不变), Result=True// ===== 阶段 6:删除 =====booldeleteOk=selectedBeam.Delete();Console.WriteLine($"6. After Delete(): ID={selectedBeam.Identifier.ID}, "+$"Result={deleteOk}");// 输出: ID=0 (归零), Valid=False, Result=True// 对象引用已失效,不可再用于其他操作}
示例 2:理解 Object 作为类型基类
usingSystem;usingSystem.Collections.Generic;usingTekla.Structures.Model;publicvoidDemonstrateObjectAsBaseClass(){// ===== Object 是 Tekla 类型系统的根基 =====// 所有 Tekla 模型对象都是 Object 的后代// 创建各种类型的对象Beambeam=newBeam();ContourPlateplate=newContourPlate();BoltArraybolts=newBoltArray();Weldweld=newWeld();Assemblyassembly=newAssembly();// 验证它们都可以向上转型为 ObjectObjectobj1=beam;// Beam → ModelObject → ObjectObjectobj2=plate;// ContourPlate → Part → ModelObject → ObjectObjectobj3=bolts;// BoltArray → ModelObject → ObjectObjectobj4=weld;// Weld → ModelObject → ObjectObjectobj5=assembly;// Assembly → ModelObject → ObjectConsole.WriteLine("=== 所有 Tekla 对象都继承自 Object ===");Console.WriteLine($"Beam is Object: {beam is Object}");Console.WriteLine($"ContourPlate is Object: {plate is Object}");Console.WriteLine($"BoltArray is Object: {bolts is Object}");Console.WriteLine($"Weld is Object: {weld is Object}");Console.WriteLine($"Assembly is Object: {assembly is Object}");// 全部输出 True// ===== Identifier 是 Object 定义的唯一公共属性 =====// 所有子类都能通过 Identifier 进行身份管理Console.WriteLine($"\n=== Identifier 多态访问 ===");List<Object>objects=newList<Object>{beam,plate,bolts,weld,assembly};foreach(Objectobjinobjects){Console.WriteLine($"{obj.GetType().Name,-20} "+$"Identifier.ID={obj.Identifier.ID}, "+$"Valid={obj.Identifier.IsValid()}");}// 输出: 所有对象的 ID 都是 0 (尚未插入数据库)}
示例 3:Object 作为容器中的多态元素
usingSystem.Collections;usingTekla.Structures.Model;publicvoidUseObjectPolymorphism(){// ===== Object 是实现多态容器的基础 =====// 通过 Identifier 统一管理不同类型的对象Modelmodel=newModel();ArrayListallObjects=newArrayList();// 获取所有模型对象(利用 Object 基类统一存储)ModelObjectEnumeratorenumerator=model.GetModelObjectSelector().GetAllObjects();while(enumerator.MoveNext()){// Current 返回 ModelObject(继承自 Object)ModelObjectcurrent=enumerator.Current;// 通过 Object 基类访问 Identifierif(current.Identifier.IsValid()){allObjects.Add(current);}}// ===== 利用 IComparable 按 ID 排序 =====// ModelObject 实现的 IComparable 基于 Identifier.IDArrayListsorted=newArrayList(allObjects);sorted.Sort();Console.WriteLine($"=== 共找到 {sorted.Count} 个对象,按 ID 排序 ===");Console.WriteLine($"{"Type",-25} {"ID",-12} {"Valid"}");Console.WriteLine(newstring('-',45));foreach(ModelObjectobjinsorted){Console.WriteLine($"{obj.GetType().Name,-25} "+$"{obj.Identifier.ID,-12} {obj.Identifier.IsValid()}");}// 示例输出:// Type ID Valid// ---------------------------------------------// Beam 1001 True// ContourPlate 1002 True// Weld 1003 True// ...}
示例 4:演示 Object 的反编译完整源码
usingSystem;usingSystem.Runtime.InteropServices;usingTekla.Structures.Internal;usingTekla.Structures.ModelInternal;namespaceTekla.Structures.Model{// COM 接口:自动生成双重接口(vtable + IDispatch)[ClassInterface(ClassInterfaceType.AutoDual)]// COM 全局唯一标识符[Guid("4668C67A-0E90-4C49-89B6-DA07FFF9A6C0")]// 支持 .NET 二进制序列化[Serializable]publicabstractclassObject{// Object 定义的唯一公共属性:模型对象标识符publicIdentifierIdentifier{get;set;}// protected 构造函数 — 外部不能直接实例化 Object// 初始化为无效 ID (0) 的默认 IdentifierprotectedObject(){this.Identifier=newIdentifier();}// 托管 .NET → 非托管 C++ 序列化// 将 Identifier 转换为 COM 互操作结构体internalvoidToStruct(refdotObject_tdotObject){dotObject.Identifier=newdotIdentifier_t(this.Identifier);}// 非托管 C++ → 托管 .NET 反序列化// 从 COM 互操作结构体恢复 IdentifierinternalvoidFromStruct(refdotObject_tdotObject){this.Identifier=dotObject.Identifier.FromStruct();}}}
七、常见问题与注意事项
- Object 不能直接实例化:
Object声明为public abstract class Object,构造函数为protected,这意味着永远不能new Object()。所有使用必须通过具体子类(Beam、ContourPlate等)进行。 - 所有 Tekla 对象都有 Identifier:由于
Object是所有模型对象的绝对根基类,Identifier属性在每一个 Tekla 对象上都可用。这是 Tekla API 最基本的类型约束——没有Identifier的对象不是 Tekla 对象。 - Identifier.ID=0 即无效:
Identifier.IsValid()通过ID > 0L判断。ID=0 表示对象未与模型数据库关联。许多子类方法(Select()、Modify()、Delete())都要求IsValid()==true - ToStruct 和 FromStruct 是 internal 的:
ToStruct(ref dotObject_t)和FromStruct(ref dotObject_t)声明为internal,普通二次开发代码无法直接调用。它们通过DelegateProxy在程序集内部被调用,用于 .NET↔C++ 数据交换。 - 三个特性都服务于 COM 互操作:
[ClassInterface(AutoDual)]使类对 COM 可见;[Guid]提供 COM 身份注册;[Serializable]支持跨应用程序域传输对象状态。这三个特性的组合确保Object能作为托管/非托管代码之间的桥梁。 - Object 只应承担"最小公共接口":
Object仅定义 1 个属性和 2 个内部方法——这是经过精心设计的。向此类添加任何新功能前应慎重考虑:它会影响整个 Tekla API 的上百个派生类。 - 序列化是单向映射的:
ToStruct()将 .NET 对象写入 COM 结构体,FromStruct()将 COM 结构体读回 .NET 对象。每次调用都会创建新的dotIdentifier_t实例,不存在引用共享。 - dotObject_t 仅一个字段:
dotObject_t结构体只有public dotIdentifier_t Identifier一个字段。这是因为在 C++ 内核层面,Object的"本质"仅是一个标识符。所有子类的额外数据由各自的dotXxx_t承载(如dotModelObject_t有 80+ 字段)。
Object 的设计是理解整个 Tekla API 架构的关键。它展示了 Tekla 对"模型对象"本质的定义——一个拥有唯一标识符、能跨越托管/非托管边界序列化的实体。在此基础上的 ModelObject 添加了 CRUD、属性系统、枚举分类等能力,而具体子类则实现最终的领域模型行为。八、总结
Object是 Tekla Open API 中所有模型对象的绝对根抽象基类,直接继承自System.Object。- 仅定义 1 个公开属性:
Identifier(ID唯一标识 +IsValid()状态判断),是所有 Tekla 对象的身份基础。 protected构造函数初始化Identifier = new Identifier()(ID=0 无效),通过子类构造链自动执行。ToStruct(ref dotObject_t)和FromStruct(ref dotObject_t)构成 .NET↔C++ 序列化桥梁,对二次开发代码不可见。- 标记
[ClassInterface(AutoDual)]、[Guid]、[Serializable]三个特性,确保 COM 互操作和跨进程序列化能力。 - 对应的互操作结构体
dotObject_t仅含一个dotIdentifier_t字段,体现"Object = 标识符"的设计哲学。 - 不定义任何枚举类型或公共方法——遵循"最小公共接口"原则,将扩展职责完全交给派生类。
- 作为整个 Tekla API 类型体系的地基,
Object的每个设计决策都影响着上方 61 种派生类型的行为。
[图 5] Object 派生类分布统计:按类别汇总的 61 种模型对象类型
尽管只有 37 行代码,Object 却是整个 Tekla Open API 体系中最被低估的类。它定义的不是"能做什么",而是"是什么"——一个跨越 .NET 和 C++ 边界的、拥有唯一身份的可序列化实体。理解 Object,就理解了 Tekla API 设计的根基。
本文适用于 Tekla Structures 2017 及以上版本。
— 关注 Tekla 开发 · 扫码交流 —
Tekla 结构开发
公众号
微信交流
扫码加好友
Tekla 二次开发:Object API 完全解析 - 钢结构资源网 Tekla插件 CAD工具 犀牛GH汉化 套料

Tekla 二次开发:Brep API 完全解析
Tekla构件比较
Tekla-NC转DXF绿色版(不限Tekla版本)
Tekla 模型自动保存工具
Tekla插件-截面拆板19.0~2021
Tekla版本转换插件(18.0~2024)v2.0
Tekla 二次开发:ContourPlate API 完全解析
Tekla工具集(18.1~2023)
