唯一元素List UniqueList
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using NUnit.Framework;
namespace SASTest
{
#region 唯一列表
//添加元素保证唯一
//修改元素保证唯一
public class UniqueList<T> : IList<T>
where T : UniqueList<T>.UniqueItem
{
List<T> list = new List<T>();
public int Count
{
get
{
return list.Count;
}
}
public int Add(T item)
{
if (!Contains(item, false))
{
list.Add(item);
item.CheckerEvent += new CallUniqueCheck(Item_CheckerEvent);
}
else
{
throw new NotUniqueException();
}
return list.Count - 1;
}
public T this[int index]
{
get
{
return list[index];
}
set
{
if (value == null)
throw new NullReferenceException();
T tmp = list[index];//备份原来的对象
list[index] = value;//修改集合中的元素
if (Contains(value, true))//修改结束判断是否有重复
{
list[index] = tmp;//如果有重复,恢复集合
throw new NotUniqueException();//抛出异常
}
if (!object.ReferenceEquals(tmp, value))//如果没有重复并且替换后的元素和原来的元素不是同一个对象,要为该元素添加属性修改检查事件
value.CheckerEvent += new CallUniqueCheck(Item_CheckerEvent);
}
}
private void Item_CheckerEvent(T item, Action<T> action)
{
T tmp = (T)Activator.CreateInstance(typeof(T));
Copy(item, tmp);//备份原来的属性值到临时对象上
action(item);
if (Contains(item, true))
{
Copy(tmp, item);//如果失败,将备份的信息恢复
throw new NotUniqueException();
}
}
private bool Contains(T item, bool edit)//检查修改后的集合是否有重复 , 对于添加元素,在添加前检查是否已经有一个同样的。如果是修改, 则先修改再看修改后是否有两个相同的元素。
{ //修改后检查,如果发现有重复,一定要恢复原来的集合
bool result = false;
if (item == null)
throw new NullReferenceException();
int count = 0;
foreach (T ui in list)
{
if (ui.Equals(item))
{
count++;
}
}
if (count <= 0)
result = false;
else if (count > 0)
{
result = true;
if (edit && count == 1)
result = false;
}
return result;
}
private static void Copy(T source, T target)//辅助方法,拷备属性
{
Type t = typeof(T);
foreach (var item in t.GetProperties())
{
try
{
item.SetValue(target, item.GetValue(source, null), null);
}
catch (Exception)
{
}
}
}
public delegate void CallUniqueCheck(T item, Action<T> action);
public abstract class UniqueItem
{
internal event UniqueList<T>.CallUniqueCheck CheckerEvent;
public void TryPropertyChange(Action<T> action)
{
if (CheckerEvent != null)
{
CheckerEvent((T)this, action);
}
else//如果是为空表明现在这个对象还没有添加到集合中
{
action((T)this);//直接修改属性
}
}
}
#region IList<T> 成员
public int IndexOf(T item)
{
return list.IndexOf(item);
}
public void Insert(int index, T item)
{
if (!Contains(item, false))
{
list.Insert(index, item);
item.CheckerEvent += new CallUniqueCheck(Item_CheckerEvent);
}
else
{
throw new NotUniqueException();
}
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
}
#endregion
#region ICollection<T> 成员
void ICollection<T>.Add(T item)
{
this.Add(item);
}
public void Clear()
{
this.list.Clear();
}
public bool Contains(T item)
{
return this.list.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
this.list.CopyTo(array, arrayIndex);
}
public bool IsReadOnly
{
get
{
return false;
}
}
public bool Remove(T item)
{
return list.Remove(item);
}
#endregion
#region IEnumerable<T> 成员
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
#endregion
#region IEnumerable 成员
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
#endregion
}
public class NotUniqueException : ApplicationException
{
public NotUniqueException()
: base("元素重复")
{
}
public NotUniqueException(string message)
: base(message)
{
}
}
#endregion
#region 测试代码
[TestFixture]
public class Tester
{
[Test]
[ExpectedException("SASTest.NotUniqueException")]
public void AddTest()//添加相同元素
{
UniqueList<MyPoint> list = new UniqueList<MyPoint>();
list.Add(new MyPoint { X = 1, Y = 1 });
list.Add(new MyPoint { X = 1, Y = 2 });
list.Add(new MyPoint { X = 2, Y = 1 });
list.Add(new MyPoint { X = 1, Y = 1 });
Assert.AreEqual(3, list.Count);//冲突时添不进相同元素
}
[Test]
[ExpectedException("SASTest.NotUniqueException")]
public void UpdatePropertyTest()//修改元素属性,使元素重复
{
UniqueList<MyPoint> list = new UniqueList<MyPoint>();
list.Add(new MyPoint { X = 1, Y = 1 });
list.Add(new MyPoint { X = 1, Y = 2 });
list.Add(new MyPoint { X = 2, Y = 1 });
list[0].X = 2;
Assert.AreEqual(1, list[0].X);//冲突时修改不了
list[0].X = 10;
Assert.AreEqual(10, list[0].X);//不冲突时可以修改
}
[Test]
[ExpectedException("SASTest.NotUniqueException")]
public void UpdateTest()//修改集合元素,使元素重复
{
UniqueList<MyPoint> list = new UniqueList<MyPoint>();
list.Add(new MyPoint { X = 1, Y = 1 });
list.Add(new MyPoint { X = 1, Y = 2 });
list.Add(new MyPoint { X = 2, Y = 1 });
list[0] = new MyPoint { X = 1, Y = 2 };
Assert.AreEqual(2, list[0].Y);
list[0] = new MyPoint { X = 10, Y = 10 };
Assert.AreEqual(10, list[0].X);
Assert.AreEqual(10, list[0].Y);
}
}
public class MyPoint : UniqueList<MyPoint>.UniqueItem
{
private int _x;
public int X
{
get { return _x; }
set
{
TryPropertyChange(p => p._x = value);
}
}
private int _y;
public int Y
{
get { return _y; }
set
{
TryPropertyChange(p => p._y = value);
}
}
public override bool Equals(object obj)
{
if (obj == null)
throw new NullReferenceException();
MyPoint point = obj as MyPoint;
return this.X.Equals(point.X) && this.Y.Equals(point.Y);
}
}
#endregion
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using NUnit.Framework;
namespace SASTest
{
#region 唯一列表
//添加元素保证唯一
//修改元素保证唯一
public class UniqueList<T> : IList<T>
where T : UniqueList<T>.UniqueItem
{
List<T> list = new List<T>();
public int Count
{
get
{
return list.Count;
}
}
public int Add(T item)
{
if (!Contains(item, false))
{
list.Add(item);
item.CheckerEvent += new CallUniqueCheck(Item_CheckerEvent);
}
else
{
throw new NotUniqueException();
}
return list.Count - 1;
}
public T this[int index]
{
get
{
return list[index];
}
set
{
if (value == null)
throw new NullReferenceException();
T tmp = list[index];//备份原来的对象
list[index] = value;//修改集合中的元素
if (Contains(value, true))//修改结束判断是否有重复
{
list[index] = tmp;//如果有重复,恢复集合
throw new NotUniqueException();//抛出异常
}
if (!object.ReferenceEquals(tmp, value))//如果没有重复并且替换后的元素和原来的元素不是同一个对象,要为该元素添加属性修改检查事件
value.CheckerEvent += new CallUniqueCheck(Item_CheckerEvent);
}
}
private void Item_CheckerEvent(T item, Action<T> action)
{
T tmp = (T)Activator.CreateInstance(typeof(T));
Copy(item, tmp);//备份原来的属性值到临时对象上
action(item);
if (Contains(item, true))
{
Copy(tmp, item);//如果失败,将备份的信息恢复
throw new NotUniqueException();
}
}
private bool Contains(T item, bool edit)//检查修改后的集合是否有重复 , 对于添加元素,在添加前检查是否已经有一个同样的。如果是修改, 则先修改再看修改后是否有两个相同的元素。
{ //修改后检查,如果发现有重复,一定要恢复原来的集合
bool result = false;
if (item == null)
throw new NullReferenceException();
int count = 0;
foreach (T ui in list)
{
if (ui.Equals(item))
{
count++;
}
}
if (count <= 0)
result = false;
else if (count > 0)
{
result = true;
if (edit && count == 1)
result = false;
}
return result;
}
private static void Copy(T source, T target)//辅助方法,拷备属性
{
Type t = typeof(T);
foreach (var item in t.GetProperties())
{
try
{
item.SetValue(target, item.GetValue(source, null), null);
}
catch (Exception)
{
}
}
}
public delegate void CallUniqueCheck(T item, Action<T> action);
public abstract class UniqueItem
{
internal event UniqueList<T>.CallUniqueCheck CheckerEvent;
public void TryPropertyChange(Action<T> action)
{
if (CheckerEvent != null)
{
CheckerEvent((T)this, action);
}
else//如果是为空表明现在这个对象还没有添加到集合中
{
action((T)this);//直接修改属性
}
}
}
#region IList<T> 成员
public int IndexOf(T item)
{
return list.IndexOf(item);
}
public void Insert(int index, T item)
{
if (!Contains(item, false))
{
list.Insert(index, item);
item.CheckerEvent += new CallUniqueCheck(Item_CheckerEvent);
}
else
{
throw new NotUniqueException();
}
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
}
#endregion
#region ICollection<T> 成员
void ICollection<T>.Add(T item)
{
this.Add(item);
}
public void Clear()
{
this.list.Clear();
}
public bool Contains(T item)
{
return this.list.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
this.list.CopyTo(array, arrayIndex);
}
public bool IsReadOnly
{
get
{
return false;
}
}
public bool Remove(T item)
{
return list.Remove(item);
}
#endregion
#region IEnumerable<T> 成员
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
#endregion
#region IEnumerable 成员
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
#endregion
}
public class NotUniqueException : ApplicationException
{
public NotUniqueException()
: base("元素重复")
{
}
public NotUniqueException(string message)
: base(message)
{
}
}
#endregion
#region 测试代码
[TestFixture]
public class Tester
{
[Test]
[ExpectedException("SASTest.NotUniqueException")]
public void AddTest()//添加相同元素
{
UniqueList<MyPoint> list = new UniqueList<MyPoint>();
list.Add(new MyPoint { X = 1, Y = 1 });
list.Add(new MyPoint { X = 1, Y = 2 });
list.Add(new MyPoint { X = 2, Y = 1 });
list.Add(new MyPoint { X = 1, Y = 1 });
Assert.AreEqual(3, list.Count);//冲突时添不进相同元素
}
[Test]
[ExpectedException("SASTest.NotUniqueException")]
public void UpdatePropertyTest()//修改元素属性,使元素重复
{
UniqueList<MyPoint> list = new UniqueList<MyPoint>();
list.Add(new MyPoint { X = 1, Y = 1 });
list.Add(new MyPoint { X = 1, Y = 2 });
list.Add(new MyPoint { X = 2, Y = 1 });
list[0].X = 2;
Assert.AreEqual(1, list[0].X);//冲突时修改不了
list[0].X = 10;
Assert.AreEqual(10, list[0].X);//不冲突时可以修改
}
[Test]
[ExpectedException("SASTest.NotUniqueException")]
public void UpdateTest()//修改集合元素,使元素重复
{
UniqueList<MyPoint> list = new UniqueList<MyPoint>();
list.Add(new MyPoint { X = 1, Y = 1 });
list.Add(new MyPoint { X = 1, Y = 2 });
list.Add(new MyPoint { X = 2, Y = 1 });
list[0] = new MyPoint { X = 1, Y = 2 };
Assert.AreEqual(2, list[0].Y);
list[0] = new MyPoint { X = 10, Y = 10 };
Assert.AreEqual(10, list[0].X);
Assert.AreEqual(10, list[0].Y);
}
}
public class MyPoint : UniqueList<MyPoint>.UniqueItem
{
private int _x;
public int X
{
get { return _x; }
set
{
TryPropertyChange(p => p._x = value);
}
}
private int _y;
public int Y
{
get { return _y; }
set
{
TryPropertyChange(p => p._y = value);
}
}
public override bool Equals(object obj)
{
if (obj == null)
throw new NullReferenceException();
MyPoint point = obj as MyPoint;
return this.X.Equals(point.X) && this.Y.Equals(point.Y);
}
}
#endregion
}