唯一元素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
}
posted @ 2009-06-13 13:54  heros  阅读(2577)  评论(0编辑  收藏  举报