Когда я пытаюсь использовать делегатов в C # для функционального решения проблемы, я сталкиваюсь с ловушкой, которой хочу поделиться. для которого я хотел бы услышать ваши предложения.
Фон
Я хочу заполнить сетку из списка объектов, где значения для отдельных столбцов получают с использованием делегатов (идея заимствована из элемент управления Philip Pipers ObjectListView ).
Дополнительно я хочу автоматически вставить столбцы, содержащие (числовую) разницу между двумя значениями.
Итак, мои объекты, имеющие свойства FirstValue
, SecondValue
и ThirdValue
, я хочу иметь столбцы с FirstValue
, (SecondValue-FirstValue)
, SecondValue
, (ThirdValue-SecondValue)
, ThirdValue
.
Я уже адаптировал существующий элемент управления grid для использования делегатов в списке объектов, эта часть отлично работает.
Первая попытка
Сначала я попробовал что-то вроде:
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));
}
};
Проблема
На функциональном языке вычисление разницы таким способом будет работать нормально, поскольку новый делегат (созданный внутри AddMyColumn
) будет использовать значение из lastGetter
во время построения. Но в C # новый делегат использует от ссылки до lastGetter
, поэтому при выполнении он использует фактическое значение во время выполнения. Таким образом, разница всегда будет построена по последнему столбцу (т. Е. 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: позволят ли они найти более чистое решение (и, следовательно, заслуживают своего имени ...)?