我正在尝试创建一个继承自现有winform TreeView控件的扩展树视图控件。在TreeViewEx类中创建了一个Load()
函数。在此函数中,dataSource在foreach中循环。这个foreach然后在循环dataSource上调用Where()
扩展方法,向它传递一个返回谓词的方法(它将当前元素作为参数)。该谓词错误地解释了传递给它的参数值。它似乎使用以前的参数值。
返回谓词之前方法中arg的值
调试器输入谓词时的arg值
最初我认为这种行为是由于我正在迭代Enumerable
而不是列表,所以我将不同的枚举更改为List但没有改变。还试图实例化返回的谓词,但没有。
加载功能:
public Func<T, Func<T, bool>> GetChildrenPredicate { get; set; }
.
.
.
public virtual void Load(List<T> dataSource = null)
{
try
{
if (CreateNode == null)
{
OnError?.Invoke(this, new ArgumentNullException("CreateNode"));
return;
}
if (GetParentKey == null)
{
OnError?.Invoke(this, new ArgumentNullException("GetParentKey"));
return;
}
if (GetChildrenPredicate == null)
{
OnError?.Invoke(this, new ArgumentNullException("GetChildrenPredicate"));
return;
}
var finalDataSource = dataSource ?? DataSource;
TreeNode node = null;
BeginUpdate();
foreach (var item in finalDataSource)
{
node = CreateNode(item);
node.Tag = item;
if (this.Nodes.Find(node.Name, true).Count() == 0)
{
var n = this.Nodes.Find(this.GetParentKey(item), true).FirstOrDefault() as TreeNode;
if (n == null)
{
this.Nodes.Add(node);
}
else
{
n.Nodes.Add(node);
}
List<T> children = finalDataSource
.ToList()
.Where(this.GetChildrenPredicate(item))
.ToList(); //this.GetChildrenPredicate is
//the property func generating the
//predicate set by a different class
if (children.Count() > 0)
{
// Recursively call this function for all childRows
Load(children);
}
}
}
EndUpdate();
}
catch (Exception ex)
{
OnError?.Invoke(this, ex);
}
}
GetChildrenPredicate:
private Func<ORM.DataModels.Menu, bool> GetChildrenPredicate(ORM.DataModels.Menu arg)
{
return (ORM.DataModels.Menu m) =>
(m.Lepere == arg.Codmen) ||
(m.Lepere == null && arg.Codmen == "_" + m.Niveau);
}
您在要检查的行上设置断点。这意味着此代码尚未执行。我可能会显示调试器缓存的上一个调用的值。
如果要检查return-expression的结果,请先将其分配给临时变量。
Func<ORM.DataModels.Menu, bool> predicate = (ORM.DataModels.Menu m) =>
(m.Lepere == arg.Codmen) ||
(m.Lepere == null && arg.Codmen == "_" + m.Niveau);
return predicate; // <== Set breakpoint here
也许首先将参数赋值给局部变量,以强制lambda使用当前值。
string codmen = arg.Codmen;
return (ORM.DataModels.Menu m) =>
(m.Lepere == codmen) ||
(m.Lepere == null && codmen == "_" + m.Niveau);
好。我找到了解决方案。实际上我并没有意识到finalDataSource
在Load()
的每次召唤中都被覆盖了。我只专注于谓词的奇怪行为。只需使用类中定义的全局DataSource属性。
List<T> children = this.DataSource.Where(this.GetChildrenPredicate(item)); //<= changed local variable finalDataSource to the defined property this.DataSource