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.InstancesIEntityCollection實現實現了像大多數的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();      }  }