c# - 我如何解决这个 lambda 表达式外部变量问题?

标签 c# lambda wpfdatagrid icustomtypedescriptor

我正在使用 PropertyDescriptor 和 ICustomTypeDescriptor ( still ) 尝试将 WPF DataGrid 绑定(bind)到一个对象,该对象的数据存储在字典中。

因为如果您向 WPF DataGrid 传递一个字典对象列表,它将根据字典的公共(public)属性(Comparer、Count、Keys 和 Values)自动生成列,我的 Person 子类 Dictionary 并实现 ICustomTypeDescriptor。

ICustomTypeDescriptor 定义了一个返回 PropertyDescriptorCollection 的 GetProperties 方法。

PropertyDescriptor 是抽象的,因此您必须对其进行子类化,我想我会有一个采用 Func 的构造函数和一个 Action 参数,用于委托(delegate)获取和设置字典中的值。

然后我为字典中的每个键创建一个 PersonPropertyDescriptor,如下所示:

            foreach (string s in this.Keys)
            {
                var descriptor = new PersonPropertyDescriptor(
                        s,
                        new Func<object>(() => { return this[s]; }),
                        new Action<object>(o => { this[s] = o; }));
                propList.Add(descriptor);
            }

问题是每个属性都有自己的 Func 和 Action,但它们都共享外部变量 s 因此尽管 DataGrid 自动生成“ID”、“FirstName”、“LastName”、“年龄”、“性别”,他们都得到并设置为“性别”,这是 foreach 循环中 s 的最终静止值。

如何确保每个委托(delegate)都使用所需的字典键,即实例化 Func/Action 时 s 的值?

非常感谢。


这是我的其他想法,我只是在这里试验这些不是“真正的”类......

// DataGrid binds to a People instance
public class People : List<Person>
{
    public People()
    {
        this.Add(new Person());
    }
}

public class Person : Dictionary<string, object>, ICustomTypeDescriptor
{
    private static PropertyDescriptorCollection descriptors;

    public Person()
    {
        this["ID"] = "201203";
        this["FirstName"] = "Bud";
        this["LastName"] = "Tree";
        this["Age"] = 99;
        this["Gender"] = "M";        
    }        

    //... other ICustomTypeDescriptor members...

    public PropertyDescriptorCollection GetProperties()
    {
        if (descriptors == null)
        {
            var propList = new List<PropertyDescriptor>();

            foreach (string s in this.Keys)
            {
                var descriptor = new PersonPropertyDescriptor(
                        s,
                        new Func<object>(() => { return this[s]; }),
                        new Action<object>(o => { this[s] = o; }));
                propList.Add(descriptor);
            }

            descriptors = new PropertyDescriptorCollection(propList.ToArray());
        }

        return descriptors;
    }

    //... other other ICustomTypeDescriptor members...

}

public class PersonPropertyDescriptor : PropertyDescriptor
{
    private Func<object> getFunc;
    private Action<object> setAction;

    public PersonPropertyDescriptor(string name, Func<object> getFunc, Action<object> setAction)
        : base(name, null)
    {
        this.getFunc = getFunc;
        this.setAction = setAction;
    }

    // other ... PropertyDescriptor members...

    public override object GetValue(object component)
    {
        return getFunc();
    }

    public override void SetValue(object component, object value)
    {
        setAction(value);
    }
}

最佳答案

简单地:

        foreach (string s in this.Keys)
        {
            string copy = s;
            var descriptor = new PersonPropertyDescriptor(
                    copy,
                    new Func<object>(() => { return this[copy]; }),
                    new Action<object>(o => { this[copy] = o; }));
            propList.Add(descriptor);
        }

对于捕获的变量,重要的是声明的地方。因此,通过在循环内声明捕获的变量,每次迭代都会获得捕获类的不同实例(循环变量 s 在技术上声明为在循环外) .

关于c# - 我如何解决这个 lambda 表达式外部变量问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2717377/

相关文章:

c# - 如何获取wpf datagrid中DatagridTemplateColumn的单元格内容?

c# - 如何使 DataGrid 看起来像 CardView?

c# - ImageList 上的 32 位图像

c# - 使用 Office 365 的 SmtpClient 速度极慢

c# - 为什么 C 和 C++ 中的 float / double 没有除余运算?

c# - 如何创建用于表达式构建的静态 lambda?

Python - 变量定义的参数的确切数量

python - lambda 函数中的多个 if 语句

c# - 更改 WPF 数据网格中滚动条的位置

c# - 如何从 token 中提取并获取声明?