gpt4 book ai didi

c# - 委托(delegate)的组成(功能陷阱)

转载 作者:太空狗 更新时间:2023-10-30 00:47:25 26 4
gpt4 key购买 nike

当尝试在 C# 中使用委托(delegate)以函数式方式解决问题时,我遇到了一个陷阱,我想与大家分享一下。为此,我想听听您的建议。

背景

我想从对象列表中填充一个网格,其中单列的值是使用委托(delegate)获取的(从 Philip Pipers ObjectListView control 借来的想法)。

此外,我想自动插入包含两个值之间(数字)差异的列。

因此我的对象具有属性 FirstValueSecondValueThirdValue 我希望列具有 FirstValue(SecondValue-FirstValue), SecondValue, (ThirdValue-SecondValue), ThirdValue.

我已经调整了现有的网格控件以在对象列表上使用委托(delegate),这部分工作正常。

第一次尝试

首先,我尝试了类似的方法:

class MyGridClass : DelegateGrid
{
DelegateGrid.ValueGetter lastGetter;

public MyGridClass() {
AddMyColumn(delegate(MyObj obj) { return obj.FirstValue; });
AddMyColumn(delegate(MyObj obj) { return obj.SecondValue; });
AddMyColumn(delegate(MyObj obj) { return obj.ThirdValue; });
}

private void AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null)
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-lastGetter(obj);
}));
base.AddColumn(new DelegateColumn(getter));
}
};

问题

在函数式语言中,以这种方式计算差异会很好,因为新委托(delegate)(在 AddMyColumn 中构造)将使用 lastGetter 的 在构建时。但在 C# 中,新委托(delegate)使用 referencelastGetter,因此在执行时,它使用执行时的实际值。因此,差异将始终针对最后一列(即 obj.ThirdValue)构建。

解决方案

我自己找到的一个解决方案是

public AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter =
new DelegateGrid.ValueGetter(lastGetter);
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-newLastGetter(obj);
}));
}
// ...
}

注意

if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter =
delegate(MyObject obj){return lastGetter(obj); };

不会解决问题。

问题

已经找到了解决方案,这部分有点形式化,但是

  • 有没有人有更好的解决方案的建议
  • 我使用的是 C#2.0,对 C#3.0 中的 lambda 表达式只有理论知识:它们是否允许更简洁的解决方案(因此名副其实...)?

最佳答案

问题只是捕获的是变量,而不是值。这是一个大致相同但稍微简单的解决方案:

public AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter = lastGetter;
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-newLastGetter(obj);
}));
}
// ...
}

基本上不需要创建新的委托(delegate)实例 - 委托(delegate)是不可变的,因此您可以通过赋值复制值。

就所捕获的值而言,这并不是一个真正的委托(delegate)特定问题——它通常是匿名方法和 lambda 表达式的常见问题。典型的例子是;

List<Action> actions = new List<Action>();
for (int i=0; i < 10; i++)
{
actions.Add(() => Console.WriteLine(i));
}
foreach (Action action in actions)
{
action();
}

这会打印 10 次“10”。要打印 0-9,您需要再次更改捕获变量的范围:

List<Action> actions = new List<Action>();
for (int i=0; i < 10; i++)
{
int copy = i;
actions.Add(() => Console.WriteLine(copy));
}
foreach (Action action in actions)
{
action();
}

关于c# - 委托(delegate)的组成(功能陷阱),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/696729/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com