.Net Framework 1.1에서 .Net Framework 2.0 으로 이동시 경험한 실패 1
CollectionBase 문제 - 임시 해결책
namespace Netron.GraphLib
{
/// <summary>
/// Collection of shape objects
/// </summary>
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("8A34971D-6811-452e-809E-160E00E94EE9")]
[Serializable] public class ShapeCollection : CollectionBase
{
#region Constructor
public ShapeCollection()
{
}
private ShapeCollection(ArrayList newarray)
{
this.InnerList.Clear();
foreach( Shape sh in newarray)
{
Add(sh);
}
}
#endregion
#region Methods
public int GetCount()
{
return this.InnerList.Count;
}
[ComVisible(false)]
public object Clone()
{
return new ShapeCollection(this.InnerList);
}
[ComVisible(false)]
public int Add(Shape shape)
{
return this.InnerList.Add(shape);
}
[ComVisible(false)]
public Shape this[int index]
{
get{
if(index>-1 && index<this.InnerList.Count)
return this.InnerList[index] as Shape;
else
return null;
}
}
[ComVisible(false)]
public bool Contains(object shape)
{
if(shape is Shape)
return this.InnerList.Contains(shape);
else
return false;
}
[ComVisible(false)]
public void Remove(Shape shape)
{
this.InnerList.Remove(shape);
}
#endregion
}
}
위와 같은 Custom Collection 이 있다고 할때 .Net Framework 2.0에서 COM Interop에서 GetEnumerator()를
호출하여 IEnumVARIANT를 얻고, 안에 담고있는 Object 배열을 얻기위해의
Next(unsigned long celt, VARIANT FAR *rgVar, unsigned long FAR *pCeltFetched ) 메서드를 호출할 경우 Collection 에서 얻은 Count(celt)만큼 pCeltFetched에 리턴되나 rgVar 은 VT_EMPTY형으로
InvalidOperationException (0x80131509 ) 에러를 리턴함.
2.0 SDK 도움말을 보면 다음과 같은 말이 나와 있음
잘못된 인수 이외의 다른 이유로 메서드를 호출할 없는 경우 InvalidOperationException이 사용됩니다. 예를 들어, InvalidOperationException은 다음과 같은 경우에 throw됩니다.
열거자를 만든 후 컬렉션의 개체가 수정되는 경우 MoveNext 메서드에 의해 예외가 throw됩니다.
메서드를 호출하기 전에 리소스 집합이 닫히는 경우
잘못된 인수로 인해 메서드를 호출할 수 없는 경우 ArgumentException이 throw되거나 해당 파생 클래스인 ArgumentNullException 또는 ArgumentOutOfRangeException 중 하나가 대신 throw됩니다.
InvalidOperationException은 0x80131509 값을 가지는 HRESULT COR_E_INVALIDOPERATION을 사용합니다.
InvalidOperationException 인스턴스의 초기 속성 값 목록에 대한 자세한 내용은 InvalidOperationException 생성자를 참조하십시오.
이 형식의 모든 public static(Visual Basic의 경우 Shared) 멤버는 스레드로부터 안전합니다. 인터페이스 멤버는 스레드로부터 안전하지 않습니다.
위의 내용대로 Next 호출시 컬렉션 개체가 수정되고 있는듯.
IEnumerable, IEnumerator 인터페이스를 상속받아 구현해주었으나 효과 없음.
IEnumerable의 메서드 GetEnumerator는 CollectionBase에 구현되어 있다.
CollectionBase와 IEnuerator을 상속받을 경우 GetEnumerator을 통해 ArrayList의 IEnumerator를 받으므로
ArrayList에 구현된 Reset, Current, MoveNext 가 호출되어 SapeCollection에 구현된 Reset, Current, MoveNext
가 무시된다.
자신만의 Custom Collection을 구현하기 위해서는 IEnumerable, IEnumerator를 상속받아 GetEnumerator,
Reset, Current, MoveNext를 정교하게 구현하여야 한다.
ShapeCollection의 경우 CollectionBase에서 제공하는 다른 Method들도 요구하므로 CollectionBase를
사용하여야 한다.
결론적으로 Next 호출시 내부적으로 MoveNext가 호출되고 이때 요소가 삭제, 추가등으로 변경되어 InvalidOperation Exception이 발생하는 것으로 생각된다. 2.0에서 왜 요소가 변경될까? 아마 CollectionBase
의 내부 구조가 변경된듯 하다.
2.0의 RegAsm.exe를 사용하여 tlb를 만들었으나 역시 상관없는둣.
1.1 도 되고 2.0, 기타 상위버전에서 확실해 돌아 갈 수 있는 해결책을 찾지못함
2.0 SDK를 사용할 수 있는 개발환경이라면(VS .NET 2005) Generic 사용을 적극 검토하라.!
1.1 이하에서 Custom Collection을 CollectionBase로 구현했다면 1.1 Runtime에서 동작하도록
강제하는 방법밖에 없는듯 하다.






