xBIM 基礎14 使用LINQ實現最佳性能(優化查詢)
- 2019 年 10 月 4 日
- 筆記
LINQ代表語言集成查詢,它是3.5版以來的.NET Framework的一部分。它實現延遲執行,這意味著您可以鏈接查詢語句,並且在您實際迭代結果之前它將不執行任何操作。您可以使用LINQ作為一個特定的語言,也可以使用擴展方法,從 System.Linq
延伸 IEnumerable<T>
的介面,並能得到參數作為lambda表達式。我們更喜歡後一種方法,但它是等效的。以下示例顯示了兩種變體都做同樣的事情。兩個查詢的結果都是枚舉具有任何開口的牆的全局唯一ID。
// LINQ 表達式 var ids = from wall in model.Instances.OfType<IIfcWall>() where wall.HasOpenings.Any() select wall.GlobalId;
//Lambda 表達式。效果與上述的 Linq 表達式相同 var ids = model.Instances .Where<IIfcWall>(wall => wall.HasOpenings.Any()) .Select(wall => wall.GlobalId);
可以在程式碼中看到 Where()
直接調用函數IModel.Instances
。IEntityCollection
實現實現了像大多數的LINQ的數據檢索方法重載 Where<T>()
,Count<T>()
,FirstOrDefault<T>()
,OfType<T>()
,它是在最低水平快速數據訪問進行了優化。所有這些方法都返回IEnumerable<T>,
因此您可以使用其他方法將其鏈接以執行進一步的選擇,聚合,排序和其他操作。 IEntityCollection
函數也使用延遲執行,因此它非常適合Linq概念。如果要多次使用結果,則應強制它枚舉。你可以通過調用一個做到這一點ToList<T>()
,ToArray<T>()
或ToDictionary<T>()
方法。
xBIM在內部使用實體類型作為第一級過濾器,因此您應始終詢問最具體的類型。請記住,它IModel.Instances
包含模型中的所有實體,通常是數十萬個對象!所以你不想迭代所有這些來做任何事情。請參閱以下好的和壞的示例,它們執行相同但不完全相同的操作:
public static void SelectionWithLinq() { const string ifcFilename = "SampleHouse.ifc"; var model = IfcStore.Open(ifcFilename); using (var txn = model.BeginTransaction()) { var requiredProducts = new IIfcProduct[0] .Concat(model.Instances.OfType<IIfcWallStandardCase>()) .Concat(model.Instances.OfType<IIfcDoor>()) .Concat(model.Instances.OfType<IIfcWindow>()); // 遍歷你所需要的實體,大概有9個 foreach (var product in requiredProducts) { // 相關業務邏輯 } txn.Commit(); } }
下面的程式碼示例大約慢了4.5倍!請不要使用這種類型的程式碼:
public static void SelectionWithoutLinqIsSLOW() { const string ifcFilename = "SampleHouse.ifc"; var model = IfcStore.Open(ifcFilename); using (var txn = model.BeginTransaction()) { //這種方式需要迭代大約 47309 個實體,而不是僅需要9個實體。 foreach (var entity in model.Instances) { if (entity is IIfcWallStandardCase || entity is IIfcDoor || entity is IIfcWindow) { // 最好不要在這裡做其他的業務邏輯 } } txn.Commit(); } }