Как я могу обойти эту внешнюю вариабельную проблему Lambda Expression?

StackOverflow https://stackoverflow.com/questions/2717377

Вопрос

Я играю с PropertyDescriptor и ICUSTOMTYPEDESSCRICTOR (еще) Попытка связывать DataGrid WPF для объекта, для которого данные хранятся в словаре.

Поскольку если вы проходите WPF DataGrid в списке объектов словаря, он будет автоматически генерировать столбцы на основе общедоступных свойств словаря (сравнительной, счетчики, ключи и значений) мой словарь подклассов моего человека и реализует ICUSTOMTYPEDEPEDESSCRICTOR.

ICUSTOMTYPEDESSCRICTOR определяет метод GetProperties, который возвращает свойство HandscriptorCollection.

PropertyDescriptor абстрактно, так что вы должны подкласс, я подумал, что у меня будет конструктор, который взял FUNC и параметры действия, которые передают получение и настройку значений в словаре.

Затем я создаю 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);
            }

Проблема в том, что каждое свойство получают свои собственные функции и действие, но все они делятся внешней переменной с Итак, хотя столбец TataGrid AutoGenerates для «ID», «первый случай», «фамилия», «возраст», «гендерные» все они получают и устанавливают против «пола», который является последним значением покоя с в петле FORACH.

Как я могу убедиться, что каждый делегат использует желаемый ключ словаря, т. Е. Значение 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);
    }
}
Это было полезно?

Решение

Решение MARC, конечно, правильно, но я подумал, что буду расширяться, почему ниже. Как большинство из нас знают, если вы объявите переменную в for или foreach заявление, это только живет только как то, что внутри, что делает его казаться Как и переменная такая же, как переменная, объявленная в отчете-блоке такого утверждения, но это не правильно.

Чтобы понять это лучше, возьмите следующую петлю. Затем я переполню «эквивалентный» цикл в то время как в то время как форма.

for(int i = 0; i < list.Length; i++)
{
    string val;
    list[i] = list[i]++;
    val = list[i].ToString();
    Console.WriteLine(val);
}

Это работает в то время как в то время как ниже: (это не совсем то же самое, потому что continue Будет действовать по-другому, но для правил охвата, это то же самое)

{
    int i = 0;
    while(i < list.Length)
    {
        {
            string val;
            list[i] = list[i]++;
            val = list[i].ToString();
            Console.WriteLine(val);
        }
        i++;
    }
}

Когда «взорвался» таким образом, объем переменных становится более четкой, и вы можете видеть, почему он всегда зафиксирует одно и то же значение «s» значение в вашей программе, и почему решение MARC показывает, где отображается ваша переменная, так что уникальный захвачен каждый раз.

Другие советы

Просто:

        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);
        }

С захваченными переменными, именно там объявлен это важно. Поэтому, объявляя захваченную переменную внутри цикла, вы получите другой экземпляр класса Capture на итерацию (переменная петли, s, технически заявлен за пределами петля).

Создать локальную копию s Внутри вашего for петля и используйте это.

for(string s in this.Keys) {
string key = s;
//...
}

Для некоторых дополнительных мыслей по этому вопросу см.

http://ericlippert.com/2009/11/12/Closing-over-the-loop-variable-consided-harmal-part-one/

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top