唯一元素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
}

你可能感兴趣的:(unique)