Working with Microsoft Visual Studio 2005 Team System (정보문화사 2006, Richard Hundhausen 저, 안재우 역)에서 일부 발췌해서 요약한 슬라이드입니다. Team System이 많이 쓰이긴 하는 것 같지만, 아직 Unit Test, Static Analysis 등은 그렇게 많이 쓰이질 않는 듯한데, 매우 유용하고 좋은 도구인 것 같습니다.
규칙 설명 System.Collections.Generic.List<T>는 성능을 위해서 디자인된 제네릭 컬렉션이며 상속성등은 고려되지 않았다. 그래서 어떤 가상 멤버도 그 안에 포함할 수가 없다. 아래의 제네릭 컬렉션은 상속성을 고려해서 디자인되었으므로, 리턴 타입/파라미터/외부 노출 형식에는 아래 타입들을 써야 할 것이다.
* System.Collections.Generic.List<T>는 MSDN을 보면 나와있듯이 ArrayList의 Generic 버전이라고 생각하면 된다. 즉, 동적으로 크기가 늘어나고 빠르게 접근할 수 있는 특정 구현 형태로 보면 될 것이다. 외부 노출/리턴 타입/파라미터 등은 각 클래스들이 관계를 맺는 방식에 영향을 줄 수 있다. 이런 곳에서 상속할 수 없는 특정 구현 형태를 사용함으로써 그것에 얽매이는 것은 매우 좋지 않다는 것이 바로 이 규칙이 말하는 바라고 생각된다.
규칙설명 클래스는 가지고 있는 관리되지 않는 리소스(파일 스트림 등의)를 제거하기 위해서 IDisposable 인터페이스를 구현하게 된다. IDisposable 형식의 인스턴스 필드가 있다는 것이 바로 그 필드가 관리되지 않는 리소스를 가지고 있다는 것을 말해 주는 것이다. 간접적으로 관리되지 않는 리소스를 가지고 있는 IDisposable 필드를 선언한 클래스는 반드시 IDisposable 인터페이스를 구현해야 한다. 또 주의해야 할 것은 직접적으로 어떤 관리되지 않는 리소스를 가지고 있지 않는 클래스는 finalizer를 구현해서는 안된다.
예제코드
[C#]
using System;
using System.IO;
namespace DesignLibrary { //규칙을 위반한 예제이다.
public class NoDisposeMethod {
FileStream newFile;
public NoDisposeMethod() {
newFile = new FileStream(@"c:\temp.txt", FileMode.Open); } }
//이 클래스 구현은 규칙을 만족한다.
public class HasDisposeMethod: IDisposable {
FileStream newFile;
public HasDisposeMethod() {
newFile = new FileStream(@"c:\temp.txt", FileMode.Open); }
public void Dispose() {
newFile.Close(); } } }
[VB.NET]
Imports System
Imports System.IO
Namespace DesignLibrary
'규칙을 위반한 예제이다
Public Class NoDisposeMethod
Dim newFile As FileStream
Sub New()
newFile = New FileStream("c:\temp.txt", FileMode.Open)
End Sub
End Class
'규칙을 만족하는 구현이다.
Public Class HasDisposeMethod
Implements IDisposable
Dim newFile As FileStream
Sub New()
newFile = New FileStream("c:\temp.txt", FileMode.Open)
End Sub
Sub Dispose() Implements IDisposable.Dispose
newFile.Close()
End Sub
End Class
End Namespace
관련 규칙 삭제가능한 필드는 삭제되어야 한다.
삭제가능한 형식은 finalizer를 선언해야 한다.
Dispose 메서드는 베이스 클래스의 Dispose 메서드를 호출해야 한다.
native 리소스를 가지고 있는 형식은 삭제가능해야 한다.
규칙 클래스 이름: DoNotDeclareStaticMembersOnGenericTypes
규칙 ID: CA1000
분류: 디자인 규칙
메시지 레벨: 에러
확실도: 95% (확실도는 코드 분석에서 이 규칙에 위반 사례를 찾는 것에 대한 것이다. 즉, 이 규칙에 위반되었다는 것에 대해서 95%의 확실도로 보증할 수 있다는 것이다)
원인: 외부에 노출된 제네릭 타입이 정적(static, vb.net에서는 shared) 멤버를 가질 때 이 규칙에 위반된다.
규칙 설명
제네릭 타입의 정적 멤버를 호출할 때는 형식 매개 변수를 반드시 명시되어야 한다. Inference(유추 - 컴파일러가 인자를 통해서 형식 인자를 자동으로 알아내는 것을 말한다)를 지원하지 않는 제네릭 인스턴스 멤버를 호출할 때도, 형식 매개 변수의 형식이 반드시 명시되어야 한다. 이 두 케이스의 형식 매개 변수를 지정하는 구문은 다르지만, 아래 예에서 보듯이 혼동되기 쉽다.
[C#]
// Static method in a generic t.
GenericType<int>.StaticMethod();
// Generic instance method that does not support inference.
someObject.GenericMethod<int>();
[VB]
'Shared method in a generic type.
GenericType(Of Integer).SharedMethod()
'Generic instance method that does not support inference.
someObject.GenericMethod(Of Integer)()
위의 두 가지 코딩 방법은 멤버가 호출될 때 형식 매개 변수를 특정한 형식으로 정하지 않기 위해서 피해야 한다. 위와 같은 코딩을 하면 결과적으로 제네릭 타입을 쓰지 않은 것과 차이가 없다. 이 위반 사항을 고치기 위해서는, 정적 멤버를 없애고 그것을 인스턴스 멤버로 바꾸어야 한다.
관련 규칙
제네릭 타입에 과도한 파라미터를 피한다.
컬렉션 타입은 제네릭 인터페이스를 구현해야 한다
제네릭 리스트를 public으로 노출하지 않는다
제네릭 타입을 중첩하지 않는다
디자인 규칙은 클래스 라이브러리 디자인 가이드라인에 따르는 지를 검사하는 규칙들의 모음이다. 닷넷의 기본적인 사상에 부합되는 클래스, 인터페이스, 예외 처리 등의 디자인이 되었는지(예:CA1020 형식이 부족한 네임스페이스를 사용하지 마십시오), .NET Class Library에서 적용된 기본적인 설계 원칙들을 따르고 있는 지(예: CA1056 Uri 속성은 문자열이면 안 됩니다), .NET Framework의 기본적인 규칙을 따로 있는지(예:CA2210 어셈블리에는 올바른 강력한 이름을 사용해야 합니다) 등을 검사하는 것이라고 할 수 있다.