هل "حدد جديد" في LINQ يؤدي الى تقييم / تحميل؟
-
03-07-2019 - |
سؤال
وأنا أحاول حاليا لإنشاء فئة التي تطبق IEnumerable<T>
من أجل بناء التسلسل الهرمي من قائمة كاملة من الكائنات التي لديها ما يشير إلى بعضهم البعض من خلال خاصية ParentId. أود أن يكتب على واجهة بطلاقة لذلك حتى أستطيع أن أفعل شيئا من هذا القبيل
IEnumerable<Tab> tabs = GetTabs();
IEnumerable<TabNode> tabNodes = tabs.AsHierarchy().WithStartLevel(2).WithMaxDepth(5);
وهكذا، حول بيان الغلة، وأتساءل عما إذا كان يمكن أن أفعل شيئا من هذا القبيل في صفي NodeHierarchy : IEnumerable<TabNode>
:
private IEnumerable<TabNode> _nodes;
public NodeHierarchy(IEnumerable<Tab> tabs)
{
_nodes = CreateHierarchy(tabs);
}
public IEnumerable<TabNode> CreateHierarchy(IEnumerable<Tab> tabs)
{
/* About this block: I'm trying to find the top level
nodes of the first tab collection, maybe this is done poorly? */
var tabIds = tabs.Select(t => t.TabID);
IEnumerable<TabNode> nodes = from tab in tabs
where !tabIds.Contains(tab.ParentId)
select new TabNode {
Tab = node,
ChildNodes = CreateHierarchy(tabs, node.TabID, 1),
Depth = 1 };
return nodes;
}
وأو ما إذا كنت قد تفعل شيئا مثل هذا:
private IEnumerable<TabNode> _nodes;
public NodeHierarchy(IEnumerable<Tab> tabs)
{
_nodes = CreateHierarchy(tabs);
}
public IEnumerable<TabNode> CreateHierarchy(IEnumerable<Tab> tabs)
{
var tabIds = tabs.Select(t => t.TabID);
IEnumerable<Tab> startingNodes = from tab in tabs
where !tabIds.Contains(tab.ParentId)
select tab;
foreach(Tab node in startingNodes)
{
yield return
new TabNode()
{
Tab = node,
ChildNodes = CreateHierarchy(tabs, node.TabID, 1),
Depth = 1
};
}
المحلول
لا، سوف select new
لا يؤدي التقييم. وهذه الخريطة لدعوة إلى:
.Select(tab => new TabNode {...})
ونلاحظ أن Select
(لLINQ إلى كائنات، على الأقل) هو في الأساس شيئا مثل:
public static IEnumerable<TDest> Select<TSource,TDest>(
this IEnumerable<TSource> source,
Func<TSource,TDest> selector)
{
foreach(TSource item in source)
{
yield return selector(source);
}
}
والنقطة الأساسية هنا يجري أنه يقيم كسول - ليس في كل مرة
. وأما النهج ينبغي أن تكون قابلة للمقارنة - والفرق الوحيد هو أنه من دون yield return
، <م> بعض م> سيتم تشغيل كود فورا - ولكن رمز فقط لبناء سلسلة .Where(...).Select(...)
- انها لن معالجة الواقع الصفوف حتى بدء بالتكرار النتيجة.
وعلاوة على ذلك، اعتمادا على مصدر البيانات، هذا النهج يمكن فعلا أن تكون أكثر كفاءة - على سبيل المثال، مع الخلفية LINQ إلى SQL، مثل مولد TSQL يمكن تخطي الأعمدة التي لا داعي لها