Есть ли способ получать уведомления, когда свойство меняет группы в отсортированной коллекции? - PullRequest
1 голос
/ 12 ноября 2011

Если говорить более конкретно, допустим, у нас есть коллекция, отсортированная по свойствам P1 и P2 следующим образом:

  • A 1
  • A 2
  • A 2
  • A 3
  • B 1
  • B 1
  • B 2
  • B 3

Когдаделая foreach через коллекцию, я хочу получать уведомления при каждом изменении свойства.
Так что для P1 мне нужны следующие 4 уведомления в этом конкретном порядке:

  1. OnBeforeGroup (P1, "A")
  2. OnAfterGroup (P1, "A")
  3. OnBeforeGroup (P1, "B")
  4. OnAfterGroup (P1, "B")

Для P2 это сделало бы 12 уведомлений, избавьте меня от списка.

Конечно, я могу сделать это в каждом случае использования, сохранив "старые" значения свойств в цикле foreach (OldP1 = P1) изапуск события / выполнение метода, когда P1! = OldP1, но это не для повторного использования.

Есть ли коллекция, которая уже реализует этот шаблон?
Если нет, есть ли какой-нибудь совет, как сделать его более пригодным для повторного использования?

Редактировать: Обратите внимание, я просто хочу получать уведомления во время цикла foreach, если какое-либо значение свойства отличается от того, которое было в предыдущей итерации, это не имеет никакого отношения к INotifyPropertyChanged и т. Д.

Ответы [ 2 ]

1 голос
/ 12 ноября 2011

.NET имеет ObservableCollection<T>, но он используется для наблюдения за изменениями, происходящими с сохраненными объектами и самой коллекцией. Ваша коллекция не меняется (учитывая, что я вас правильно понял) - вы просто хотите получать уведомления во время цикла, если какое-либо значение свойства отличается от того, которое было в предыдущей итерации.

Что-то, что может указать вам правильное направление с точки зрения наличия кода многократного использования:

public class PropertyWatcher<TSource>
{
    // initialization code omitted
    private Dictionary<string, object> previousValues;
    private Dictionary<string, Func<TSource, object>> selectors; 

    public void RegisterWatcher<TSource>(Func<TSource, object> propertySelector, 
        string propertyName)
    {
        this.selectors.Add(propertyName, propertySelector);
        this.previousValues.Add(propertyName, null);
    }

    public void NotifyIfDifferent<TObject, TPropertyType>(TSource currentItem)
    {
        foreach (var key in this.selectors.Keys)
        {
            var selector = this.selectors[key];
            var currentValue = selector(currentItem);
            if (!currentValue.Equals(this.previousValues[key]))
            {
                // raise notification, event; antyhing to your liking
            }

            this.previousValues[key] = currentValue;
        }
    }
}

И, предполагая, что мы имеем дело с P1 и P2 свойствами, которые вы упомянули, использование будет выглядеть следующим образом:

var list = new List<SomeObject>(); // list of items you intend to watch
var watcher = new PropertyWatcher<SomeObject>();
watcher.RegisterWatcher((SomeObject o) => o.P1, "P1");
watcher.RegisterWatcher((SomeObject o) => o.P2, "P2");
foreach (var item in list)
{
    watcher.NotifyIfDifferent(item);
}

Это далеко не полное решение. Он должен работать, когда речь идет о простых значениях (поэтому .Equals может легко выполнять сравнение). Конечно, вам все равно нужно добавить какое-то событие в класс PropertyWatcher и, возможно, настроить его здесь и там - но я думаю, что общую идею довольно легко понять.

Хотя для более сложных сценариев, я полагаю, вам придется работать с более общим подходом.

0 голосов
/ 12 ноября 2011

Не уверен, что у C # есть аспекты, но это может быть одно место, чтобы посмотреть.В противном случае вы можете добавить делегат изменения в ваш класс, а затем в заданной части методов вашего свойства вы можете вызвать делегат:

private delegate void beforeGroup( MyObject current, MyObject changesTo );
private delegate void afterGroup( MyObject current, MyObject changedFrom );

public MyObject P1 {
    get {
        return p1;
    }
    set {
        beforeGroup( p1, value );
        MyObject oldValue = p1;
        p1 = value;
        afterGroup( p1, oldValue );
    }
}
...