Мнение хотело: Прерывание изменений в списках/наборах

Компилятор C знает о пробеле, но это не различает пробелы, вкладки или новые строки.

, Если Вы имеете в виду, как, у меня есть новая строка в строке в макросе, тогда:

#define SOME_STRING "Some string\n with a new line."

будет работать.

5
задан Community 23 May 2017 в 12:26
поделиться

4 ответа

Я бы посоветовал создать что-то похожее на ObservableCollection , где это возможно. В частности, я бы посоветовал следовать существующим методам уведомления об изменении коллекции. Что-то вроде:

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

Это будет следовать установленным шаблонам, чтобы клиенты уже были знакомы с открытыми интерфейсами - три интерфейса уже существуют. Использование существующих интерфейсов также позволит более правильно взаимодействовать с другими уже существующими технологиями .NET, такими как WPF (который связывается с интерфейсами INotifyPropertyChanged и INotifyCollectionChanged .)

Я бы хотел. ожидайте, что интерфейс 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; }
}

Если вы хотите добавить поддержку отмены, просто добавьте доступное для записи свойство bool Cancel в CollectionChangingEventArgs , которое коллекция будет читать, чтобы определить, выполнять ли изменение, которое вот-вот должно произойти.

Я полагаю, это подпадает под ваш вариант 2. Это правильный путь, потому что для правильного взаимодействия с другими технологиями .net, которые отслеживают изменения коллекций, вам все равно придется реализовать его для INotifyCollectionChanged . Это определенно будет соответствовать политике «наименьшего сюрприза» в вашем интерфейсе.

net, которые отслеживают изменение коллекций, вам все равно придется реализовать его для INotifyCollectionChanged . Это определенно будет соответствовать политике «наименьшего сюрприза» в вашем интерфейсе.

net, которые отслеживают изменение коллекций, вам все равно придется реализовать его для INotifyCollectionChanged . Это определенно будет соответствовать политике «наименьшего сюрприза» в вашем интерфейсе.

5
ответ дан 13 December 2019 в 19:29
поделиться

Я бы рекомендовал отдельные мероприятия. Мне это кажется более ясным.

РЕДАКТИРОВАТЬ:

Возможно, вы захотите рассмотреть событие до и после, такое как Inserting, Inserted или, как у ребят из VB, BeforeInsert, AfterInsert. Это даст пользователю большую гибкость.

2
ответ дан 13 December 2019 в 19:29
поделиться

Have a look at this link, maybe that is what you are looking for, a Generic List based object that acts as a List but with built-in events such as BeforeItemAdded, ItemAdded, BeforeItemRemoved, ItemRemoved and ItemsCleared.

Hope this helps, Tom. :)

2
ответ дан 13 December 2019 в 19:29
поделиться

На самом деле, вы будете удивлены, насколько легко вы можете создать подобную коллекцию. Take a look at System.Collections.ObjectModel.Collection. That is a class which is intended to be used for such things. It has a few virtual methods (one for every operation) which you can override and control very well.

I would recommend Option 1, since it is more clear and straightforward.

Here is an example which you can use for such purposes:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;

namespace TestGround
{
    public class MyCollection<T> : Collection<T>
    {
        public class ListChangeEventArgs : EventArgs
        {
            public IEnumerable<T> ItemsInvolved { get; set;}

            public int? Index { get; set;}
        }

        public delegate void ListEventHandler(object sender, ListChangeEventArgs e);

        public event ListEventHandler Inserting;

        public event ListEventHandler Setting;

        public event ListEventHandler Clearing;

        public event ListEventHandler Removing;

        public MyCollection() : base() { }

        public MyCollection(IList<T> innerList) : base(innerList) { }

        protected override void ClearItems()
        {
            Clearing(this, new ListChangeEventArgs()
            {
                 Index = null,
                 ItemsInvolved = this.ToArray(),
            });
            base.ClearItems();
        }

        protected override void InsertItem(int index, T item)
        {
            Inserting(this, new ListChangeEventArgs()
            {
                Index = index,
                ItemsInvolved = new T[] { item },
            });
            base.InsertItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            Removing(this, new ListChangeEventArgs()
            {
                Index = index,
                ItemsInvolved = new T[] { this[index] },
            });
            base.RemoveItem(index);
        }

        protected override void SetItem(int index, T item)
        {
            Setting(this, new ListChangeEventArgs()
            {
                Index = index,
                ItemsInvolved = new T[] { item },
            });
            base.SetItem(index, item);
        }
    }
}

You could also modify the ListChangeEventArgs to have a bool property with the name "Cancel", and control wheter to do the change or not in the collection.

The after events could also be useful, if you need such functionality.

Of course, you won't have to use all events of every collections, or if it is really necessary, there may be other ways to solve the problem depending on why do you need this functionality.

EDIT:

If you really only want to validate the items and set their Parent property to an entity instance, you can actually write a collection which does exactly that, or something that generalizes the problem in another way. You could pass it a delegate which validates the item, and and another which tells it what to do when an item is added or removed.

For example, you can achieve this using the Action delegate.

You could consume it this way:

class Order : Entity
{
    public Order()
    {
        OrderItems = new MyCollection2<OrderItem>(
            //Validation action
            item => item.Name != null && item.Name.Length < 20,
            //Add action
            item => item.Parent = this,
            //Remove action
            item => item.Parent = null
        );
    }

    ...
}

The major benefit of this approach is that you don't have to bother with event handlers or delegates, beacuse all that you need can be written using lambda expressions, however if you need something more advanced, you can always use a real delegate instead of them.

This is an example of the collection:

public class MyCollection2<T> : Collection<T>
{
    public Func<T, bool> Validate { get; protected set; }

    public Action<T> AddAction { get; protected set; }

    public Action<T> RemoveAction { get; protected set; }

    public MyCollection2(Func<T, bool> validate, Action<T> add, Action<T> remove)
        : base()
    {
        Validate = Validate;
        AddAction = add;
        RemoveAction = remove;
    }

    protected override void ClearItems()
    {
        foreach (var item in this)
        {
            RemoveAction(item);
        }
        base.ClearItems();
    }

    protected override void InsertItem(int index, T item)
    {
        if (Validate(item))
        {
            AddAction(item);
            base.InsertItem(index, item);
        }
    }

    protected override void RemoveItem(int index)
    {
        RemoveAction(this[index]);
        base.RemoveItem(index);
    }

    protected override void SetItem(int index, T item)
    {
        if (Validate(item))
        {
            RemoveAction(this[index]);
            AddAction(item);
            base.SetItem(index, item);
        }
    }
}

For such purposes, I think this is the cleanest way to go.

2
ответ дан 13 December 2019 в 19:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: