다음은 MyClassCollection 클래스의 디버깅 시의 표현되는 정보입니다.
List<T>와는 다르게 내부의 요소의 값을 확인하는데 어려움이 존재합니다.
이것을 List<T>처럼 구성해 보겠습니다.
[System.Diagnostics.DebuggerDisplay("{Value}", Name = "{Name}")] class MyClass { public String Name; public String Value; public MyClass(String name, String value) { this.Name = name; this.Value = value; } } [System.Diagnostics.DebuggerDisplay("Count = {Count}")] [System.Diagnostics.DebuggerTypeProxy(typeof(CollectionDebugView))] class MyClassCollection : CollectionBase, ICollection { public MyClass Add(String name, String value) { Int32 i = base.InnerList.Add(new MyClass(name, value)); return base.InnerList[i] as MyClass; } } class CollectionDebugView { private ICollection collection; public CollectionDebugView(ICollection collection) { this.collection = collection; } [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)] public MyClass[] MyClasses { get { List<myclass> myClasses = new List<myclass>(collection.Count); foreach (object key in collection) { MyClass myClass = key as MyClass; if (myClass != null) { myClasses.Add(myClass); } } return myClasses.ToArray(); } } } class Program { static void Main(string[] args) { MyClassCollection col = new MyClassCollection(); col.Add("Name1", "Value1"); } }
위처럼 구성하면 아래와 같이 보이게 됩니다.
다음은 MyClass 클래스의 디버깅 시 표현되는 정보입니다.
확장을 해야 내부 정보의 확인이 가능합니다.
cls 오른쪽의 RiSvE.MyClass(클래스 명) 대신 value1(Value 필드)을 표현하고 싶을 경우에 두 가지 방법이 있습니다.
첫 번째 방법은 ToString 메서드를 오버라이드 하는 것입니다.
class MyClass { public String Name; public String Value; public MyClass(String name, String value) { this.Name = name; this.Value = value; } public override string ToString() { return Value; } }
두 번째 방법은 DebuggerDisplayAttribute 특성을 이용하는 것입니다.
[System.Diagnostics.DebuggerDisplay("{Value}", Name = "{Name}")] class MyClass { public String Name; public String Value; public MyClass(String name, String value) { this.Name = name; this.Value = value; } }
첫 번째와 두 번째의 경우 결과가 비슷해 보이지만 List<T> 개체에 추가된 후에 보면 차이점이 발생합니다.
첫 번째의 경우입니다.
0번째 요소가 value1임을 나타내고 있습니다.
두 번째의 경우입니다.
name1 요소가 value1임을 나타내고 있습니다.
두 번째의 경우 이름과 값이 같이 볼 수 있으므로 더 효율적인 디버깅이 가능할 것입니다.
AppStylist 프로그램을 이용하여 스킨을 설정하려고 할 때 Editors 탭을 선택하면
"동일한 키를 사용하는 항목이 이미 추가되었습니다."
라는 메시지로 에러 화면이 발생합니다.
이것이 UltraTimeZoneEditor에서 TimeZone 리스트를 가져오기 위한 작업을 할 때
다음 두 곳중 레지스트리가 존재하는 한곳의
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones
STD의 값을 키값으로 이용하고 있습니다.
이 때 이용하는 키 값이 중복이 되어서 그렇습니다.
Windows Server 2003 R2 한글 PC의 경우엔 다음 두 곳에서 중복 키가 존재했습니다.(PC마다 다를 수 있습니다.)
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Central Europe Standard Time
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Central European Standard Time
동일 키가 존재하면 STD값을 다르게 처리하면 됩니다.
(Windows 7의 경우에는 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Central Europe Standard Time의 STD값 뒤에 스페이스 하나가 더 들어가 있습니다.)
다음 소스는 제가 검사할 때 이용한 소스입니다.
private static void CheckTimeZones() { string name = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"; string name2 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"; RegistryKey key = null; key = Registry.LocalMachine.OpenSubKey(name, false); if (key == null) { key = Registry.LocalMachine.OpenSubKey(name2, false); } if (key == null) { return; } string[] subKeyNames = key.GetSubKeyNames(); if (subKeyNames == null) { return; } Dictionarydic = new Dictionary (subKeyNames.Length); RegistryKey key2 = null; for (int i = 0; i < subKeyNames.Length; i++) { name = subKeyNames[i]; if (name != null) { key2 = key.OpenSubKey(name, false); if (key2 != null) { string displayName = key2.GetValue("Display") as string; string standardName = key2.GetValue("Std") as string; try { dic.Add(standardName, displayName); } catch { throw new Exception(key2.Name + "의 Std값이 중복되었습니다."); } } } } }