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