Отсоединить обработчик событий от динамического объекта - PullRequest
0 голосов
/ 27 июня 2019

Я пытаюсь отсоединить event handler, используя dynamic объект. Я не использовал dynamic много, и я не уверен, где я иду не так, как надо. Исключение, которое я получаю:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException

'объект' не содержит определения для 'CollectionChanged'

[Fact]
public void Test()
{
    var foo = new Foo();
    foo.Bars = new ObservableCollection<Bar>();
    foo.ClearDelegates();
}
Dictionary<string, object> _values;
Dictionary<string, NotifyCollectionChangedEventHandler> _collectionChangedDelegates;

public void ClearDelegates()
{
    foreach (var kvp in _values)
    {
        var currentValue = _values[kvp.Key];
        if (currentValue == null)
            continue;

        var type = currentValue.GetType();

        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ObservableCollection<>))
        {
            dynamic observableCollection = currentValue;
            observableCollection.CollectionChanged -= _collectionChangedDelegates[kvp.Key];
        }
    }
}
class Foo : DomainObject
{
    public ObservableCollection<Bar> Bars
    {
        get { return GetValue<ObservableCollection<Bar>>(nameof(Bars)); }
        set { SetValue(nameof(Bars), value); }
    }
}
class DomainObject
{
    Dictionary<string, object> _values = new Dictionary<string, object>();

    Dictionary<string, NotifyCollectionChangedEventHandler> _collectionChangedDelegates =
        new Dictionary<string, NotifyCollectionChangedEventHandler>();


    public void ClearDelegates()
    {
        foreach (var kvp in _values)
        {
            var currentValue = _values[kvp.Key];
            if (currentValue == null)
                continue;

            var type = currentValue.GetType();

            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ObservableCollection<>))
            {
                dynamic observableCollection = currentValue;
                observableCollection.CollectionChanged -= _collectionChangedDelegates[kvp.Key];
            }
        }

        _collectionChangedDelegates.Clear();
    }


    protected T GetValue<T>(string propertyName)
    {
        return (T)_values[propertyName];
    }

    protected void SetValue<T>(string propertyName, ObservableCollection<T> value)
    { 
        if (value != null)
            HookupCollectionDelegates(propertyName, value);

        Set(propertyName, value);
    }

    protected void SetValue<T>(string propertyName, T value)
    {
        Set(propertyName, value);
    }


    void Set<T>(string propertyName, T value)
    {
        _values[propertyName] = value;
        OnPropertyChanged(propertyName);
    }

    void HookupCollectionDelegates<T>(string propertyName, ObservableCollection<T> collection)
    {
        var collectionChangedDelegate = delegate(object sender, NotifyCollectionChangedEventArgs e)
        {
            // do work
        };
        collection.CollectionChanged += collectionChangedDelegate;

        if (_collectionChangedDelegates.ContainsKey(propertyName))
            _collectionChangedDelegates[propertyName] = collectionChangedDelegate;
        else
            _collectionChangedDelegates.Add(propertyName, collectionChangedDelegate);
    }
}

Ответы [ 2 ]

3 голосов
/ 01 июля 2019

Мне тоже нравятся новые функции, но мы не должны забывать старые. Ваши словари выглядят как отношения. Я думаю, что это Join время, поэтому помогите нам LINQ.

Dictionary<string, object> _values;
Dictionary<string, NotifyCollectionChangedEventHandler> _collectionChangedDelegates;

void ClearDelegates()
{
    foreach (var i in
        _values.Join(_collectionChangedDelegates,
                     outer => outer.Key,
                     inner => inner.Key,
                     (outer, inner) =>
                     new
                     {
                         Target = (INotifyCollectionChanged)outer.Value,
                         EventHandler = inner.Value
                     })) // expected, you manage your dictionaries carefully
        i.Target.CollectionChanged -= i.EventHandler;

    _collectionChangedDelegates.Clear();
}
2 голосов
/ 27 июня 2019

Чтобы избежать проблем, связанных с run-time dynamic, оставайтесь строго набранными .Обратите внимание, событие CollectionChanged определено в INotifyCollectionChanged, а не в конкретном ObservableCollection<T>, так что на самом деле не нужно dynamic.Этот код помогает избежать проблем в compile-time.

Dictionary<string, object> _values;
Dictionary<string, NotifyCollectionChangedEventHandler> _collectionChangedDelegates;

void ClearDelegates()
{
    foreach(var key in _values.Keys)
        if (_values[key] is INotifyCollectionChanged value && 
            _collectionChangedDelegates.TryGetValue(key, out var handler))
            value.CollectionChanged -= handler;
    _collectionChangedDelegates.Clear();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...