意见想要:拦截对列表/集合的更改

Vij*_*tel 5 c# domain-driven-design bindinglist observablecollection

虽然BindingList<T>ObservableCollection<T>提供了检测列表更改的机制,但它们不支持在更改发生之前检测/拦截更改的机制.

我正在写几个接口来支持这个,但我想画出你的意见.

选项1:列表为每种类型的操作引发事件

在这里,消费者可能会编写如下代码:

public class Order : Entity
    {
        public Order()
        {
            this.OrderItems = new List<OrderItem>();
            this.OrderItems.InsertingItem += new ListChangingEventHandler<OrderItem>(OrderItems_InsertingItem);
            this.OrderItems.SettingItem += new ListChangingEventHandler<OrderItem>(OrderItems_SettingItem);
            this.OrderItems.RemovingItem += new ListChangingEventHandler<OrderItem>(OrderItems_RemovingItem);
        }

        virtual public List<OrderItem> OrderItems { get; internal set; }

        void OrderItems_InsertingItem(object sender, IOperationEventArgs<OrderItem> e)
        {
            if (!validationPasses)
            {
                e.Cancel = true;
                return;
            }

            e.Item.Parent = this;
        }

        void OrderItems_SettingItem(object sender, IOperationEventArgs<OrderItem> e)
        {
            if (!validationPasses)
            {
                e.Cancel = true;
                return;
            }

            e.Item.Parent = this;
        }

        void OrderItems_RemovingItem(object sender, IOperationEventArgs<OrderItem> e)
        {
            if (!validationPasses)
            {
                e.Cancel = true;
                return;
            }

            e.Item.Parent = null;
        }

    }
Run Code Online (Sandbox Code Playgroud)

选项2:列表引发单个事件,并根据事件参数确定操作

在这里,消费者可能会编写如下代码:

public class Order : Entity
    {
        public Order()
        {
            this.OrderItems = new List<OrderItem>();
            this.OrderItems.ListChanging += new ListChangingEventHandler<OrderItem>(OrderItems_ListChanging);
        }

        virtual public List<OrderItem> OrderItems { get; internal set; }

        void OrderItems_ListChanging(object sender, IOperationEventArgs<OrderItem> e)
        {
            switch (e.Action)
            {
                case ListChangingType.Inserting:
                case ListChangingType.Setting:
                    if (validationPasses)
                    {
                        e.Item.Parent = this;
                    }
                    else
                    {
                        e.Cancel = true;
                    }
                    break;

                case ListChangingType.Removing:
                    if (validationPasses)
                    {
                        e.Item.Parent = null;
                    }
                    else
                    {
                        e.Cancel = true;
                    } 
                    break;
            }
        }

    }
Run Code Online (Sandbox Code Playgroud)

背景:我正在编写一组代表DDD核心组件的通用接口/类,我正在使用源代码(因此需要创建友好的接口).

这个问题是关于使界面尽可能具有内聚性,以便消费者可以在不丢失核心语义的情况下派生和实现自己的集合.

PS:请不要为每个列表建议使用AddXYZ()RemoveXYZ()方法,因为我已经打了折扣.

PPS:我必须包括使用.NET 2.0的开发人员:)


相关问题.

Gre*_*g D 5

我建议创建与ObservableCollection<T>适当的地方相似的东西.具体来说,我建议遵循现有的收集变更通知技术.就像是:

class MyObservableCollection<T> 
    : INotifyPropertyChanging,   // Already exists
      INotifyPropertyChanged,    // Already exists
      INotifyCollectionChanging, // You'll have to create this (based on INotifyCollectionChanged)
      INotifyCollectionChanged   // Already exists
{ }
Run Code Online (Sandbox Code Playgroud)

这将遵循既定模式,以便客户端已经熟悉暴露的接口 - 已经存在三个接口.使用现有接口还可以与其他现有的.NET技术进行更好的交互,例如WPF(INotifyPropertyChangedINotifyCollectionChanged接口绑定).

我希望INotifyCollectionChanged界面看起来像:

public interface INotifyCollectionChanged
{
    event CollectionChangingEventHandler CollectionChanging;
}

public delegate void CollectionChangingEventHandler(
    object source, 
    CollectionChangingEventArgs e
);

/// <remarks>  This should parallel CollectionChangedEventArgs.  the same
/// information should be passed to that event. </remarks>
public class CollectionChangingEventArgs : EventArgs
{
    // appropriate .ctors here

    public NotifyCollectionChangedAction Action { get; private set; }

    public IList NewItems { get; private set; }

    public int NewStartingIndex { get; private set; }

    public IList OldItems { get; private set; }

    public int OldStartingIndex { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

如果您希望添加取消支持,只需添加一个可写bool Cancel属性CollectionChangingEventArgs,该集合将读取该属性以确定是否执行即将发生的更改.

我认为这属于你的选项2.这是要走的路,因为要与监控不断变化的集合的其他.net技术进行适当的互操作,你无论如何都必须实现它INotifyCollectionChanged.这绝对会遵循您界面中"最少惊喜"的政策.