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
}