从动态对象分离事件处理程序

时间:2019-06-27 16:31:18

标签: c# dynamic reflection

我正在尝试使用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 个答案:

答案 0 :(得分:3)

我也喜欢新功能,但我们不应该忘记旧功能。您的字典看起来像一个关系。我想现在是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(); }

app_lang

答案 1 :(得分:2)

要避免受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();
}