I'm trying to serialize a class with protobuf-net which contains an immutable collection as a member.
The collection type, ImmutableList<T>, implements ICollection<T> but returns true for the IsReadOnly property. So any attempts to modify it throw an exception.
Protobuf-net seems to rely on being able to call Add(T) after creating a collection in order to populate it. This obviously won't work with an immutable collection, which is a shame because protobuf-net works beautifully with all my other data types, which are also immutable.
So my question is, what options do I have to be able to serialize such collections?
The code for ImmutableList<T> is listed below:
public sealed class ImmutableList<T> : IList<T>, IList
{
private readonly T[] m_Items;
public ImmutableList(IEnumerable<T> source)
{
m_Items = source.ToArray();
}
public T[] ToArray()
{
T[] newArray = new T[m_Items.Length];
m_Items.CopyTo(newArray, 0);
return newArray;
}
private static void ThrowNotSupported()
{
throw new NotSupportedException("The attempted operation was not supported as the collection is read-only.");
}
#region IList<T> Members
int IList.Add(object value)
{
ThrowNotSupported();
return -1;
}
void IList.Clear()
{
ThrowNotSupported();
}
void IList<T>.Insert(int index, T item)
{
ThrowNotSupported();
}
void IList.Insert(int index, object value)
{
ThrowNotSupported();
}
void IList.Remove(object value)
{
ThrowNotSupported();
}
void IList.RemoveAt(int index)
{
ThrowNotSupported();
}
void IList<T>.RemoveAt(int index)
{
ThrowNotSupported();
}
T IList<T>.this[int index]
{
get
{
return m_Items[index];
}
set
{
ThrowNotSupported();
}
}
object IList.this[int index]
{
get
{
return m_Items[index];
}
set
{
ThrowNotSupported();
}
}
public T this[int index]
{
get
{
return m_Items[index];
}
}
bool IList.Contains(object value)
{
return Array.IndexOf(m_Items, value) != -1;
}
int IList.IndexOf(object value)
{
return Array.IndexOf(m_Items, value);
}
public int IndexOf(T item)
{
return Array.IndexOf(m_Items, item);
}
bool IList.IsFixedSize
{
get
{
return true;
}
}
#endregion
#region ICollection<T> Members
void ICollection<T>.Add(T item)
{
ThrowNotSupported();
}
void ICollection<T>.Clear()
{
ThrowNotSupported();
}
bool ICollection<T>.Remove(T item)
{
ThrowNotSupported();
return false;
}
object ICollection.SyncRoot
{
get
{
return m_Items;
}
}
bool ICollection.IsSynchronized
{
get
{
return true;
}
}
public bool Contains(T item)
{
return IndexOf(item) != -1;
}
public void CopyTo(T[] array, int arrayIndex)
{
m_Items.CopyTo(array, arrayIndex);
}
void ICollection.CopyTo(Array array, int index)
{
m_Items.CopyTo(array, index);
}
public int Count
{
get
{
return m_Items.Length;
}
}
public bool IsReadOnly
{
get
{
return true;
}
}
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)m_Items).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_Items.GetEnumerator();
}
#endregion
}
At the moment there is no support for that; but it seems a reasonable scenario. It depends on what you mean (comments) by "out of the box"; if you mean "today, without code changed", it would need to use a surrogate against the DTO, or a shim property that exposed the immutable list as a mutable one; if you mean "moving forwards", I suspect we could look at list-constructors that take (perferable) IEnumerable[<T>] or (less preferable, but doable) T[], and simply construct the list after buffering the data.
Related
This question already has answers here:
How to serialize/deserialize a custom collection with additional properties using Json.Net
(6 answers)
Closed 7 years ago.
I created a custom List class that maintains a set of item ids for performance reasons:
public class MyCustomList : List<ItemWithID>
{
private HashSet<int> itemIDs = new HashSet<int>();
public MyCustomList()
{
}
[JsonConstructor]
public MyCustomList(IEnumerable<ItemWithID> collection)
: base(collection)
{
itemIDs = new HashSet<int>(this.Select(i => i.ID));
}
public new void Add(ItemWithID item)
{
base.Add(item);
itemIDs.Add(item.ID);
}
public new bool Remove(ItemWithID item)
{
var removed = base.Remove(item);
if (removed)
{
itemIDs.Remove(item.ID);
}
return removed;
}
public bool ContainsID(int id)
{
return itemIDs.Contains(id);
}
}
I want to deserialize this List from a simply JSON array e.g.:
JsonConvert.DeserializeObject<MyCustomList>("[{ID:8},{ID:9}]");
this will cause JSON.NET to call only the empty constructor, so my itemIDs list remains empty. Also the Add method is not called.
How does JSON.NET add the items to the list so I can add logic at that place.
(this is about deserialization without properties that should be persistent in the json string, so the suggested duplicate question has nothing to do with this one)
Solution:
public class MyCustomList : IList<ItemWithID>
{
private HashSet<int> itemIDs = new HashSet<int>();
private List<ItemWithID> actualList = new List<ItemWithID>();
public void Add(ItemWithID item)
{
actualList.Add(item);
itemIDs.Add(item.ID);
}
public bool Remove(ItemWithID item)
{
var removed = actualList.Remove(item);
if (removed)
{
itemIDs.Remove(item.ID);
}
return removed;
}
public bool ContainsID(int id)
{
return itemIDs.Contains(id);
}
public int IndexOf(ItemWithID item)
{
return actualList.IndexOf(item);
}
public void Insert(int index, ItemWithID item)
{
actualList.Insert(index, item);
itemIDs.Add(item.ID);
}
public void RemoveAt(int index)
{
itemIDs.Remove(actualList[index].ID);
actualList.RemoveAt(index);
}
public ItemWithID this[int index]
{
get
{
return actualList[index];
}
set
{
actualList[index] = value;
if (!itemIDs.Contains(value.ID))
{
itemIDs.Add(value.ID);
}
}
}
public void Clear()
{
actualList.Clear();
itemIDs.Clear();
}
public bool Contains(ItemWithID item)
{
return actualList.Contains(item);
}
public void CopyTo(ItemWithID[] array, int arrayIndex)
{
actualList.CopyTo(array, arrayIndex);
}
public int Count
{
get { return actualList.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public IEnumerator<ItemWithID> GetEnumerator()
{
return actualList.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
You could deserialize to the form the constructor expects, then call that yourself.
var collection = JsonConvert.DeserializeObject<ItemID[]>("[{ID:8},{ID:9}]");
var aCustomList = new MyCustomList(collection);
Your problem isn't with JSON deserialization, your MyCustomList class needs to derive from IList if you want to be able to override the Add method. See THIS for details.
I am looking for a collection where no element can exist more than once, and are also indexed. Similar to Dictionary, but without Key, just Value. Similar to a HashSet, but indexed so I can easily retrieve an element without iterating over the collection. I hope this makes sense. :)
You can use a HashSet. It is "indexed", after all, performance would be lacking if it weren't.
Use the Contains method to "retrieve" an element. If you want to remove it as well, use Remove.
Both methods are O(1) operations.
You can use a Dictionary<T, T> for that and insert elements using Add(value, value).
However, that only makes sense if your type properly implements Equals(object) and GetHashCode(). If it doesn't, two different instanced will never be equal and the HashSet<T>'s Contains(T) method already tells you whether you have the element reference of nor.
HashSet class is best for your work. I won't allow duplicate entries.
Note that the HashSet.Add(T item) method returns a bool -- true if the item was added to the collection; false if the item was already present.
Simply you can add an Extension method to throw exception as
public static void AddOrThrow<T>(this HashSet<T> hash, T item)
{
if (!hash.Add(item))
throw new ValueExistingException();
}
The easiest way to do this is make a class that implements IList<T> but uses a List<T> and HashSet<T> internally. You then just have each method act on each collection as needed.
using System;
using System.Collections.Generic;
namespace Example
{
public class UniqueList<T> : IList<T>
{
private readonly List<T> _list;
private readonly HashSet<T> _hashset;
public UniqueList()
{
_list = new List<T>();
_hashset = new HashSet<T>();
}
public UniqueList(IEqualityComparer<T> comparer)
{
_list = new List<T>();
_hashset = new HashSet<T>(comparer);
}
void ICollection<T>.Add(T item)
{
Add(item);
}
public bool Add(T item)
{
var added = _hashset.Add(item);
if (added)
{
_list.Add(item);
}
return added;
}
public void RemoveAt(int index)
{
_hashset.Remove(_list[index]);
_list.RemoveAt(index);
}
public T this[int index]
{
get { return _list[index]; }
set
{
var oldItem = _list[index];
_hashset.Remove(oldItem);
var added = _hashset.Add(value);
if (added)
{
_list[index] = value;
}
else
{
//Put the old item back before we raise a exception.
_hashset.Add(oldItem);
throw new InvalidOperationException("Object already exists.");
}
}
}
public int IndexOf(T item)
{
return _list.IndexOf(item);
}
void IList<T>.Insert(int index, T item)
{
Insert(index, item);
}
public bool Insert(int index, T item)
{
var added = _hashset.Add(item);
if (added)
{
_list.Insert(index, item);
}
return added;
}
public void Clear()
{
_list.Clear();
_hashset.Clear();
}
public bool Contains(T item)
{
return _hashset.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_list.CopyTo(array, arrayIndex);
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
var removed = _hashset.Remove(item);
if (removed)
{
_list.Remove(item);
}
return removed;
}
public int Count
{
get { return _list.Count; }
}
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
I did explicit implementations of Add and Insert so I could give them versions that returned a bool to tell if the operation succeeded or not. I could not return a value in the T this[int index] setter so I have it throw a InvalidOperationException if you attempt to insert a duplicate.
It does not throw if you do ICollection.Add on a duplicate, it just does not add it. This is because that is the behavior HashSet<T>.ICollection<T>.Add has and i wanted to mimic it.
What is the most efficient (in terms of speed) implementation of UniqueQueue and UniqueReplacementQueue collections in .NET considering the fact that the speed of Enqueue and Dequeue operations is equally important.
UniqueQueue is a queue where duplicates are not possible. So if I push an element to the queue it is added in only case it doesn't already exist in the queue.
UniqueReplacementQueue is a queue where duplicates are not possible either. The difference is that if I push an element which already exists in the queue, it replaces the existing element at the same position. It makes sense for reference types.
My current implementation of UniqueQueue and UniqueReplacementQueue:
sealed class UniqueQueue<T> : IQueue<T>
{
readonly LinkedList<T> list;
readonly IDictionary<T, int> dictionary;
public UniqueQueue(LinkedList<T> list, IDictionary<T, int> dictionary)
{
this.list = list;
this.dictionary = dictionary;
}
public int Length
{
get { return list.Count; }
}
public T Dequeue()
{
if (list.Count == 0)
{
throw new InvalidOperationException("The queue is empty");
}
var element = list.First.Value;
dictionary.Remove(element);
list.RemoveFirst();
return element;
}
public void Enqueue(T element)
{
dictionary[element] = 0;
if (dictionary.Count > list.Count)
{
list.AddLast(element);
}
}
}
sealed class UniqueReplacementQueue<T> : IQueue<T>
{
readonly LinkedList<T> list;
readonly IDictionary<T, T> dictionary;
public UniqueReplacementQueue(LinkedList<T> list, IDictionary<T, T> dictionary)
{
this.list = list;
this.dictionary = dictionary;
}
public int Length
{
get { return list.Count; }
}
public T Dequeue()
{
if (list.Count == 0)
{
throw new InvalidOperationException("The queue is empty");
}
var element = dictionary[list.First.Value];
dictionary.Remove(element);
list.RemoveFirst();
return element;
}
public void Enqueue(T element)
{
dictionary[element] = element;
if (dictionary.Count > list.Count)
{
list.AddLast(element);
}
}
}
This is pretty old, but how about a class that has an internal HashSet, and Queue. A custom method for Enqueue firsts tries to add it to the hashset. if the HashSet.Add call returns false, we do not enqueue it. HashSet.Add() is an O(1) operation if the set is of a size large enough to hold all elements.
The only drawback to this is memory usage if this is a concern for you. Here is an implementation:
public class UniqueQueue<T> : IEnumerable<T> {
private HashSet<T> hashSet;
private Queue<T> queue;
public UniqueQueue() {
hashSet = new HashSet<T>();
queue = new Queue<T>();
}
public int Count {
get {
return hashSet.Count;
}
}
public void Clear() {
hashSet.Clear();
queue.Clear();
}
public bool Contains(T item) {
return hashSet.Contains(item);
}
public void Enqueue(T item) {
if (hashSet.Add(item)) {
queue.Enqueue(item);
}
}
public T Dequeue() {
T item = queue.Dequeue();
hashSet.Remove(item);
return item;
}
public T Peek() {
return queue.Peek();
}
public IEnumerator<T> GetEnumerator() {
return queue.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return queue.GetEnumerator();
}
}
The HashSet is used whenever it can because it is typically faster. This could be nicer if the maintainers of .NET marked these methods as virtual, but alas here we are.
How about this?
//the UniqueQueueItem has the key in itself,
//and implements the IUniqueQueueItemable to copy the other values.
//For example:
class TestUniqueQueueItem : IUniqueQueueItemable<TestUniqueQueueItem>
{
//Key
public int Id { get; set; }
public string Name { get; set; }
public override int GetHashCode()
{
return Id;
}
//To copy the other values.
public void CopyWith(TestUniqueQueueItem item)
{
this.Name = item.Name;
}
public override bool Equals(object obj)
{
return this.Id == ((TestUniqueQueueItem)obj).Id;
}
}
internal interface IUniqueQueueItemable<in T>
{
void CopyWith(T item);
}
class UniqueQueue<T> where T: IUniqueQueueItemable<T>
{
private readonly bool _isReplacementQueue;
private readonly Queue<T> _queue;
private readonly Dictionary<T, T> _dictionary;
public UniqueQueue(): this(false)
{
}
public UniqueQueue(bool isReplacementQueue)
{
_isReplacementQueue = isReplacementQueue;
_queue = new Queue<T>();
_dictionary = new Dictionary<T, T>();
}
public void Enqueue(T item)
{
if(!_dictionary.Keys.Contains(item))
{
_dictionary.Add(item, item);
_queue.Enqueue(item);
}
else
{
if(_isReplacementQueue)
{
//it will return the existedItem, which is the same key with the item
//but has different values with it.
var existedItem = _dictionary[item];
//copy the item to the existedItem.
existedItem.CopyWith(item);
}
}
}
public T Dequeue()
{
var item = _queue.Dequeue();
_dictionary.Remove(item);
return item;
}
}
This question already has answers here:
Immutable collections?
(10 answers)
Closed 9 years ago.
It seems to me there is an extreme lack of safe, immutable collection types for .NET, in particular BCL but I've not seen much work done outside either. Do anyone have any pointers to a (preferably) production quality, fast, immutable collections library for .NET. A fast list type is essential. I'm not yet prepared to switch to F#.
*Edit: Note to searchers, this is being rolled into the BCL soon: .NET immutable collections
You might want to take a look at the Microsoft.FSharp.Collections namespace in the FSharp.Core assembly. You do not have to program in F# to make use of these types.
Keep in mind that the names will be different when used from outside F#. For example, the Map in F# is known as FSharpMap from C#.
The .NET BCL team has released a Immutable Collections preview for .NET 4.5
Functional-dotnet by Alexey Romanov
Sasa by Sandro Magi
Kinet by Tony Morris
I wrote an ImmutableList<T> class some time ago :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class ImmutableList<T> : IList<T>, IEquatable<ImmutableList<T>>
{
#region Private data
private readonly IList<T> _items;
private readonly int _hashCode;
#endregion
#region Constructor
public ImmutableList(IEnumerable<T> items)
{
_items = items.ToArray();
_hashCode = ComputeHash();
}
#endregion
#region Public members
public ImmutableList<T> Add(T item)
{
return this
.Append(item)
.AsImmutable();
}
public ImmutableList<T> Remove(T item)
{
return this
.SkipFirst(it => object.Equals(it, item))
.AsImmutable();
}
public ImmutableList<T> Insert(int index, T item)
{
return this
.InsertAt(index, item)
.AsImmutable();
}
public ImmutableList<T> RemoveAt(int index)
{
return this
.SkipAt(index)
.AsImmutable();
}
public ImmutableList<T> Replace(int index, T item)
{
return this
.ReplaceAt(index, item)
.AsImmutable();
}
#endregion
#region Interface implementations
public int IndexOf(T item)
{
if (_items == null)
return -1;
return _items.IndexOf(item);
}
public bool Contains(T item)
{
if (_items == null)
return false;
return _items.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
if (_items == null)
return;
_items.CopyTo(array, arrayIndex);
}
public int Count
{
get
{
if (_items == null)
return 0;
return _items.Count;
}
}
public IEnumerator<T> GetEnumerator()
{
if (_items == null)
return Enumerable.Empty<T>().GetEnumerator();
return _items.GetEnumerator();
}
public bool Equals(ImmutableList<T> other)
{
if (other == null || this._hashCode != other._hashCode)
return false;
return this.SequenceEqual(other);
}
#endregion
#region Explicit interface implementations
void IList<T>.Insert(int index, T item)
{
throw new InvalidOperationException();
}
void IList<T>.RemoveAt(int index)
{
throw new InvalidOperationException();
}
T IList<T>.this[int index]
{
get
{
if (_items == null)
throw new IndexOutOfRangeException();
return _items[index];
}
set
{
throw new InvalidOperationException();
}
}
void ICollection<T>.Add(T item)
{
throw new InvalidOperationException();
}
void ICollection<T>.Clear()
{
throw new InvalidOperationException();
}
bool ICollection<T>.IsReadOnly
{
get { return true; }
}
bool ICollection<T>.Remove(T item)
{
throw new InvalidOperationException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
#region Overrides
public override bool Equals(object obj)
{
if (obj is ImmutableList<T>)
{
var other = (ImmutableList<T>)obj;
return this.Equals(other);
}
return false;
}
public override int GetHashCode()
{
return _hashCode;
}
#endregion
#region Private methods
private int ComputeHash()
{
if (_items == null)
return 0;
return _items
.Aggregate(
983,
(hash, item) =>
item != null
? 457 * hash ^ item.GetHashCode()
: hash);
}
#endregion
}
All methods that modify the collection return a modified copy. In order to fulfill with the IList<T> interface contract, the standard Add/Remove/Delete/Clear methods are implemented explicitly, but they throw an InvalidOperationException.
This class uses a few non-standard extension methods, here they are :
public static class ExtensionMethods
{
public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item)
{
return source.Concat(new[] { item });
}
public static IEnumerable<T> SkipFirst<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
bool skipped = false;
foreach (var item in source)
{
if (!skipped && predicate(item))
{
skipped = true;
continue;
}
yield return item;
}
}
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> source, int index)
{
return source.Where((it, i) => i != index);
}
public static IEnumerable<T> InsertAt<T>(this IEnumerable<T> source, int index, T item)
{
int i = 0;
foreach (var it in source)
{
if (i++ == index)
yield return item;
yield return it;
}
}
public static IEnumerable<T> ReplaceAt<T>(this IEnumerable<T> source, int index, T item)
{
return source.Select((it, i) => i == index ? item : it);
}
}
And here's a helper class to create instances of ImmutableList<T> :
public static class ImmutableList
{
public static ImmutableList<T> CreateFrom<T>(IEnumerable<T> source)
{
return new ImmutableList<T>(source);
}
public static ImmutableList<T> Create<T>(params T[] items)
{
return new ImmutableList<T>(items);
}
public static ImmutableList<T> AsImmutable<T>(this IEnumerable<T> source)
{
return new ImmutableList<T>(source);
}
}
Here's a usage example :
[Test]
public void Test_ImmutableList()
{
var expected = ImmutableList.Create("zoo", "bar", "foo");
var input = ImmutableList.Create("foo", "bar", "baz");
var inputSave = input.AsImmutable();
var actual = input
.Add("foo")
.RemoveAt(0)
.Replace(0, "zoo")
.Insert(1, "bar")
.Remove("baz");
Assert.AreEqual(inputSave, input, "Input collection was modified");
Assert.AreEqual(expected, actual);
}
I can't say it's production quality, as I haven't tested it thoroughly, but so far it seems to work just fine...
C5 springs to mind, but I'm not sure how fast it is. It has been around for years, and is very stable.
Additionally, List<T>.AsReadOnly() does the job rather well IMO, but unfortunately there is no equivalent for dictionaries or arbitrary ICollection<T>'s.
You may look at Extras or System.collections.concurrent tutorial
You could try BclExtras by JaredPar.
Setup
C# WinForms Application.
Summary
Binding a dictionary to a datagridview.
Updating the dictionary automatically updates the datagrid.
The datagrid does not lose focus when the update happens.
The binding works both ways (editing values in the grid updates the dictionary.
Scenario
I have a class that calculates values
based on data from a database.
The data in this database constantly changes so hence, the calculated values change too.
These calculated values are added to the properties of a custom object "MyCustomObject".
Each "MyCustomObject" is then added to a dictionary (or the custom object is updated if it already exists).
The Dictionary is bound to a datagrid.
The idea
The idea is that the calculated vales continually change and thus update the dictionary which in turn updates the datagrid.
Users who are interacting with the datagrid need to be able to see these changes automatically.
It is imperative that the currently selected row in the datagrid does not lose focus when the grid is updated with the new custom object values.
The binding must work both ways (editing values in the grid updates the dictionary too.
Question
How can I implement this automatic binding so that I get the requirements that I need?
I have already written the code to do all of the calculations and add/update the dictionary of MyCustomObjects.
Examples of how to implement this datagrid binding would be greatly appreciated.
In order to accomplish this, your Dictionary would need to implement IBindingList and fire the ListChanged event whenever changes were made. Here's a sample (very) barebones implementation of IDictionary<TKey, TValue> that also implements IBindingList:
public class BindableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IBindingList
{
private Dictionary<TKey, TValue> source = new Dictionary<TKey, TValue>();
void IBindingList.AddIndex(PropertyDescriptor property) { }
object IBindingList.AddNew() { throw new NotImplementedException(); }
bool IBindingList.AllowEdit { get { return false; } }
bool IBindingList.AllowNew { get { return false; } }
bool IBindingList.AllowRemove { get { return false; } }
void IBindingList.ApplySort(PropertyDescriptor property, ListSortDirection direction) { }
int IBindingList.Find(PropertyDescriptor property, object key) { throw new NotImplementedException(); }
bool IBindingList.IsSorted { get { return false; } }
void IBindingList.RemoveIndex(PropertyDescriptor property) { }
void IBindingList.RemoveSort() { }
ListSortDirection IBindingList.SortDirection { get { return ListSortDirection.Ascending; } }
PropertyDescriptor IBindingList.SortProperty { get { return null; } }
bool IBindingList.SupportsChangeNotification { get { return true; } }
bool IBindingList.SupportsSearching { get { return false; } }
bool IBindingList.SupportsSorting { get { return false; } }
int System.Collections.IList.Add(object value) { throw new NotImplementedException(); }
void System.Collections.IList.Clear() { Clear(); }
bool System.Collections.IList.Contains(object value) { if (value is TKey) { return source.ContainsKey((TKey)value); } else if (value is TValue) { return source.ContainsValue((TValue)value); } return false; }
int System.Collections.IList.IndexOf(object value) { return -1; }
void System.Collections.IList.Insert(int index, object value) { throw new NotImplementedException(); }
bool System.Collections.IList.IsFixedSize { get { return false; } }
bool System.Collections.IList.IsReadOnly { get { return true; } }
void System.Collections.IList.Remove(object value) { if (value is TKey) { Remove((TKey)value); } }
void System.Collections.IList.RemoveAt(int index) { throw new NotImplementedException(); }
object System.Collections.IList.this[int index] { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
private ListChangedEventHandler listChanged;
event ListChangedEventHandler IBindingList.ListChanged
{
add { listChanged += value; }
remove { listChanged -= value; }
}
protected virtual void OnListChanged(ListChangedEventArgs e)
{
var evt = listChanged;
if (evt != null) evt(this, e);
}
public void Add(TKey key, TValue value)
{
source.Add(key, value);
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
public bool Remove(TKey key)
{
if (source.Remove(key))
{
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
return true;
}
return false;
}
public TValue this[TKey key]
{
get
{
return source[key];
}
set
{
source[key] = value;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
((ICollection<KeyValuePair<TKey, TValue>>)source).Add(item);
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
if (((ICollection<KeyValuePair<TKey, TValue>>)source).Remove(item))
{
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
return true;
}
return false;
}
public bool ContainsKey(TKey key) { return source.ContainsKey(key); }
public ICollection<TKey> Keys { get { return source.Keys; } }
public bool TryGetValue(TKey key, out TValue value) { return source.TryGetValue(key, out value); }
public ICollection<TValue> Values { get { return source.Values; } }
public void Clear() { source.Clear(); }
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) { return ((ICollection<KeyValuePair<TKey, TValue>>)source).Contains(item); }
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { ((ICollection<KeyValuePair<TKey, TValue>>)source).CopyTo(array, arrayIndex); }
public int Count { get { return source.Count; } }
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly { get { return ((ICollection<KeyValuePair<TKey, TValue>>)source).IsReadOnly; } }
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return source.GetEnumerator(); }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
bool ICollection.IsSynchronized { get { return false; } }
object ICollection.SyncRoot { get { return null; } }
void ICollection.CopyTo(Array array, int arrayIndex) { ((ICollection)source).CopyTo(array,arrayIndex); }
}
Unfortunately, the selected row may or may not change, depending on which grid you're using. Your best bet is to save off the key of the selected row whenever it changes, then reselect that row (if present) when the dictionary is updated. Otherwise, there's no way to guarantee that you'll maintain the selection.