Undo Framework Design (Revert the changes in the collection) Requirement is to monitor the changes in a List&lt;T&gt;, possible changes are Add / Remove / Update, which are registered in an Audit log, which I do in the code underneath using a Dictionary. Now user can take an action to revert each of the operations, using an integrated Action delegate. Each operation runs its respective Revert operation. Please note here undo is not about notification, like ObservableCollection&lt;T&gt; but removal at the later time based on user discretion.
Following is my design, please suggest, what shall be done to further improvise.



public class ActionWrapper&lt;T&gt;
{
    public int Index {get;set;}
    public T OriginalValue {get;set;}
    public T NewValue {get;set;}
    public Action&lt;int,T&gt; Action {get;set;}  
}

public class ChangeList&lt;T&gt; : List&lt;T&gt; 
                             where T:class,IEquatable&lt;T&gt;
{
    public Dictionary&lt;T,ActionWrapper&lt;T&gt;&gt; ActionMap {get;set;}

    public ChangeList()
    {
        ActionMap = new Dictionary&lt;T,ActionWrapper&lt;T&gt;&gt;();
    }

    public new void Add(T item)
    {
        base.Add(item); 

        var actionWrapper = new ActionWrapper&lt;T&gt;
        {
            Action = new Action&lt;int,T&gt;(RevertAdd),
            Index = this.FindIndex(x =&gt; x.Equals(item)),
            NewValue = item,
            OriginalValue = null
        };

        ActionMap[actionWrapper.NewValue] = actionWrapper;
    }

    public new void Remove(T item)
    {   
        var actionWrapper = new ActionWrapper&lt;T&gt;
        {
            Action = new Action&lt;int, T&gt;(RevertRemove),
            Index = this.FindIndex(x =&gt; x.Equals(item)),
            NewValue = null,
            OriginalValue = item
        };

        if(actionWrapper.Index &lt; 0)
           return;

        base.Remove(actionWrapper.OriginalValue);

        ActionMap[actionWrapper.OriginalValue] = actionWrapper;
    }

    public void Update(T actualValue,T newValue)
    {
        var actionWrapper = new ActionWrapper&lt;T&gt;
        {
            Action = new Action&lt;int, T&gt;(RevertUpdate),
            Index = this.FindIndex(x =&gt; x.Equals(actualValue)),
            NewValue = newValue,
            OriginalValue = actualValue
        };

        if (actionWrapper.Index &lt; 0)
            return;

        base[actionWrapper.Index] = newValue;

        ActionMap[actionWrapper.NewValue] = actionWrapper;
    }

    public void RevertAdd(int index, T actual)
    {
        base.Remove(actual);    
    }

    public void RevertRemove(int index,T actual)
    {
        base.Add(actual);
    }

    public void RevertUpdate(int index,T actual)
    {
        base[index] = actual;
    }
}


Use Case

void Main()
{
    var changeList = new ChangeList&lt;string&gt;();
    changeList.Add("Person1");
    changeList.Add("Person2");
    changeList.Add("Person3");
    changeList.Add("Person4");
    changeList.Add("Person5");
    changeList.Add("Person6");
    changeList.Add("Person7");
    changeList.Dump(); // Print statement

    var actionMapUpdateAdd = changeList.ActionMap["Person5"];
    actionMapUpdateAdd.Action(actionMapUpdateAdd.Index, actionMapUpdateAdd.NewValue);
    changeList.Dump(); // Print statement

    changeList.Update("Person7","Person77");
    changeList.Dump(); // Print statement

    var actionMapUpdate = changeList.ActionMap["Person77"];
    actionMapUpdate.Action(actionMapUpdate.Index,actionMapUpdate.OriginalValue);     
    changeList.Dump(); // Print statement

    changeList.Remove("Person6");
    changeList.Dump(); // Print statement

    var actionMapRemove = changeList.ActionMap["Person6"];
    actionMapRemove.Action(actionMapRemove.Index, actionMapRemove.OriginalValue);
    changeList.Dump(); // Print statement
}
Edge cases

This fails to handle several edge-cases:


Undoing a remove action multiple times results in that item being added back multiple times.
Undoing an update action after other items have been inserted at a lower index causes the wrong items to be replaced.
Lists can contain duplicate items, but only the last operation for each distinct item is remembered.
Updating an item leaves the add-operation for the original item, but attempting to undo that add-operation fails unless the update action has first been undone.


As the last point demonstrates, you can't just undo an action without undoing all actions that followed it first. If you do want to support something like that, you'll have to clearly define the requirements and figure out what the desired behavior is for a variety of edge-cases. You'll also want to make this information available to those that will use this code (documentation, see below).

Implementation notes


Hiding methods with new is rarely a good idea: (changeList as IList&lt;string&gt;).Add("untracked item"); probably does not do what you want it to do. In this case, don't inherit from List&lt;T&gt;: implement the necessary interfaces manually, and use an internal List&lt;T&gt; for the actual storage.
List&lt;T&gt; (and IList&lt;T&gt;) provides some other methods (Insert, [int index] and Clear) that are not being 'intercepted', resulting in untracked changes.
Undoing an action is complicated. Why should the caller need to know whether to use NewValue or OriginalValue? That makes it difficult to use correctly. Why does the caller need to pass in any arguments at all? Why use a wrapper class if you can just create a closure with all the necessary state?
Try to use clear, descriptive names. UndoableAction and Undo are much clearer than ActionWrapper and Action, and Replace is a more accurate description of what the Update method does.
Those RevertAdd/Remove/Update methods don't seem to be intended for public use, so don't make them public. They only clutter the interface of your class.
Those ActionWrapper properties should probably not be public either, but if they have to be, then at least make them read-only. You don't want other code to be able to mess with the internals of your change-tracking/undo system. The same goes for that ActionMap property: it should only be exposed as a get-only IReadOnlyDictionary.
Documentation is entirely absent. That makes it even more difficult to tell how this class is meant to be used (or even what its exact purpose is), and various details such as Remove only removing the first matching item are left to the caller to figure out. It also makes it difficult for others to distinguish between intended and incorrect behavior.


Alternative design

I'd go for a different design, one that doesn't expose internal details, doesn't allow for out-of-order undoing (which means less edge-cases), and that provides a simple interface that's easy to use correctly (note how it's not possible to undo the same action multiple times):

public class ChangeTrackingList&lt;T&gt; // implements IList&lt;T&gt; and/or other interfaces
{
    private List&lt;T&gt; _items = new List&lt;T&gt;();
    private Stack&lt;Action&gt; _undoActions = new Stack&lt;Action&gt;();

    public bool UndoLastAction()
    {
        if (!_undoActions.Any())
            return false;

        var undoLastAction = _undoActions.Pop();
        undoLastAction();
        return true;
    }

    public void Add(T item)
    {
        _items.Add(item);

        // Ensure that this item gets removed, and not an identical earlier occurrence:
        var index = _items.Count - 1;
        _undoActions.Push(() =&gt; _items.RemoveAt(index));
    }

    ...
}