1. 접근 가능한 필드를 속성으로 대체한다
1、. .NET 데이터 바인딩은 데이터 바인딩만 지원하며, 속성을 사용하면 데이터 바인딩의 이점을 누릴 수 있습니다. 2. 속성에 대한 접근 및 설정 과정에서 lock을 사용해 멀티스레딩 지원을 추가할 수 있습니다.
2. 읽기(런타임 상수)와 const(컴파일 타임 상수)
1. const는 원시 타입, 열거, 문자열에만 사용할 수 있으며, 읽기 전용은 모든 타입을 사용할 수 있습니다; 2. const 값은 컴파일 시점에 특정 상수로 대체되어, 참조에서 const와 readonly 값이 모두 사용될 경우, readonly로 변경되면 원래 설계의 의도, 즉 변경된 어셈블리를 다시 컴파일하여 새 상수 값을 다시 참조해야 하는 의도가 바뀝니다. 3. const는 읽기 전용보다 효율적이지만 적용의 유연성을 잃습니다.
3. IS와 AS
1. 두 경우 모두 런타임 시 타입 변환으로, 연산자는 참조 타입에서만 사용할 수 있고, is는 값과 참조 타입을 사용할 수 있습니다; 2. 일반적인 관행은 IS를 사용해 타입을 결정한 후, 선택적으로 강한 타입 변환 연산자(오페레이터가 정의한 변환)를 선택하는 것입니다.
4. #if #endif条件编译 대신 조건 속성
1. 조건 속성은 메서드 수준에서만 사용되며, 타입, 속성 등과 같은 다른 항목들은 유효하지 않습니다. 그리고 #if #endif则不受此限制; 2. 조건 속성은 컴파일 조건에 대해 여러 개의 OR(OR) 연산을 추가할 수 있으며, #if #endif则可以添加与(AND) [여기서 완전히 다른 별도의 기호로 정의할 수 있음]; 3. ConditioanlAttribute 정의는 프로그램을 더 유연하게 만들기 위해 별도의 메서드에 배치할 수 있습니다.
5. ToString() 메서드 제공
1. 사용자에게 더 친근한 방식으로 상세한 정보를 제공할 수 있습니다; 2. IFormatter.ToString() 메서드를 사용하여 더 유연한 맞춤화를 제공하고, IFormatProvider와 ICustomFormatter 인터페이스를 추가하면 메시지 출력을 더 맞춤화할 수 있습니다.
6. 가치와 참조 유형의 차이점
1. 값 타입은 다형성을 지원하지 않으며, 다형성은 애플리케이션이 운영하는 데이터를 저장하는 데 적합하며, 참조는 애플리케이션 동작을 정의하는 데 적합한 다형성을 지원합니다. 2. 값 유형으로 정의된 배열의 경우, 프로그램의 성능을 크게 향상시킬 수 있습니다; 3. 값 타입은 힙 메모리 조각화, 메모리 가비지, 간접 접근 시간이 적으며, 메서드에서 반환은 내부 구조가 외부 세계에 노출되지 않도록 복제 형태로 수행됩니다. 4. 가치 유형은 다음과 같은 상황에서 사용됩니다: 유형들의 책임은 주로 데이터 저장에 사용됩니다; 공용 인터페이스는 일부 데이터 멤버 접근 속성으로 완전히 정의되며; 하위 직업은 존재하지 않으며; 다형성 행동은 절대 존재하지 않습니다.
7. 값 타입은 가능한 한 상수와 원자 타입으로 구현되어야 합니다
1. 코드를 작성하고 유지하기 쉽게 만들고; 2. 상수 초기화를 위한 세 가지 전략: 구성에서; 식물 방법; 가변 보조 클래스(예: StringBuilder)를 구성하세요.
8. 0이 유효한 지위에 합당한지 확인한다
1. 값 유형의 기본 상태는 0이어야 합니다; 2. 열거 타입의 0은 무효가 되어서는 안 됩니다; FlagsAttribute에서는 0 값이 유효한 상태임을 보장하는 역할을 합니다; 3. 문자열이 비어 있으면 문자열을 반환할 수 있습니다. 빈 문자열은 빈 문자열입니다.
9. 평등한 판단을 위한 다중 표현 관계
1. ReferenceEquals()는 참조가 같음을 결정하며, 두 참조가 동일한 객체를 참조할 때 이 기준이 참이어야 합니다. 2. 정적 Equals() 방법을 사용하여 먼저 참조 판단을 하고, 그 다음 가치 유형을 판단합니다; 3. 참조 타입 판단을 위해 값 의미론을 사용할 때 Rewrite Equals() 메서드를 사용할 수 있습니다. 4. Equals() 메서드를 다시 쓸 때는 GetHashCode() 메서드도 함께 다시 작성해야 하며, 동시에 오퍼레이터==() 연산도 제공되어야 합니다.
10. GetHashCode() 방법의 한계를 이해하기
1. GetHashCode()는 해시 기반 ** 정의된 키(예: HashTable이나 Dictionary)의 해시 값에만 적용됩니다; 2. GetHashCode()는 이에 대응하는 세 가지 규칙을 따라야 합니다: 두 개의 동일한 객체가 동일한 해시 코드를 반환해야 합니다; 는 인스턴스 불변이어야 한다; 해시 함수는 모든 정수에 걸쳐 무작위 분포를 생성해야 합니다.
11. foreach 루프 문장 사용에 우선권을 부여한다
1. foreach는 for 루프의 배열 경계에 대한 컴파일러의 검사를 제거할 수 있습니다; 2. foreach의 원형 변수는 읽기 전용이며, ** 객체의 객체 타입이 잘못되었을 때 예외를 던지는 명시적 변환이 있습니다; 3. foreach를 사용하려면 **는 다음과 같습니다: 공개 GetEnumberator() 메서드를 가지고; IEnumberable 인터페이스는 명시적으로 구현되어 있습니다. IEnumerator 인터페이스가 구현되어 있으며; 4. foreach는 리소스 관리의 이점을 가져올 수 있는데, 컴파일러가 IDisposable 인터페이스를 결정할 수 있다면 최적화된 try를 사용할 수 있기 때문입니다... 마지막으로 차단;
12. 기본 필드의 초기화가 할당 문장보다 더 낫다
1. 필드 수명은 기본값으로 값 타입을 0으로 초기화하고 참조 타입을 널로 만듭니다. 2. 동일한 객체를 여러 번 초기화하면 코드 실행 효율이 감소합니다. 3. 필드 초기화를 구성자에 넣는 것은 예외 처리에 유리하다.
13. 정적 생성자를 사용하여 정적 멤버를 초기화합니다
1. 정적 생성자는 클래스의 메서드, 변수 또는 속성에 접근하기 전에 실행됩니다; 2. 정적 필드는 정적 생성자보다 먼저 실행되며, 정적 생성자는 예외 처리에 적합합니다.
14. 컨스트럭터 체인(in . NET 4.0은 이미 선택적 매개변수로 이 문제를 해결하고 있습니다)
1. 이를 사용하여 초기화 작업을 다른 생성자에게 넘기고, 기본 클래스의 생성자를 호출하기 위해 base를 사용합니다; 2. 유형 인스턴스의 연산 순서는 다음과 같습니다: 모든 정적 필드를 0으로 설정; 정적 필드 초기화 실행; 기본 클래스를 실행하는 정적 생성자; 현재 타입을 실행하는 정적 생성자; 모든 인스턴스 필드를 0으로 설정하세요; 인스턴스 필드 초기화 실행; 적절한 기본 클래스 인스턴스 생성자를 실행하세요; 현재 타입의 인스턴스 생성자를 실행하세요.
15. 사용과 try/final(최종 진술) 사용으로 자원을 정리하는 데 사용해
IDisposable 인터페이스의 Dispose() 메서드에서는 GC.SuppressFinalize()를 사용하여 가비지 콜렉터에 최종 작업이 더 이상 수행되지 않음을 알릴 수 있습니다.
16. 메모리 가레딧 최소화
1. 힙 위의 객체를 할당하고 파괴하는 데 추가 프로세서 시간이 소요됩니다; 2. 할당된 객체 수를 줄이는 기법: 자주 사용되는 국소 변수를 필드로 진급; 특정 타입을 표현하는 싱글턴 객체의 일반적인 인스턴스를 저장하는 클래스를 제공합니다. 3. 복잡한 문자열 연산을 위해 StringBuilder를 사용하세요.
17. 짐 싸기와 풀기를 최소화한다
1. 타입이 System.Object로 암묵적으로 변환되는 부분에 주의해야 하며, 값 타입은 System.Object 타입으로 대체되어서는 안 됩니다; 2. 타입 대신 인터페이스를 사용하면 박스링, 즉 인터페이스에서 값 타입을 구현한 후 인터페이스를 통해 멤버를 호출하는 것을 피할 수 있습니다.
18. 표준 폐기 모드 구현
1. 비메모리 자원을 사용하려면 최종자가 있어야 하며, 가비지 컬렉터는 종료되지 않은 메모리 객체를 완료한 후 구현된 파이널라이저 객체를 종료 큐에 추가합니다. 그리고 가비지 콜렉터는 이 객체들에 대한 파이널라이저를 실행하는 새 스레드를 시작합니다. 이렇게 하면 관리되지 않은 메모리 자원이 해제되지 않아 발생하는 메모리 누수 문제를 피할 수 있습니다. 2. IDisposable.Dispose() 메서드를 사용하려면 네 가지 작업이 필요합니다: 모든 관리되지 않은 자원을 해제하는 것; 모든 관리 자원을 해제하고; Dispose() 실행되었는지 나타내는 상태 마커를 설정하세요; GC.SuppressFinalize(this)를 호출하여 객체의 종료 연산을 취소합니다; 3. 다형성이 필요한 타입에 보호된 가상 메서드 Dispose()를 추가하면, 파생 클래스는 이 메서드를 다시 작성하여 작업을 해제합니다. 4. IDisoposable 인터페이스가 필요한 타입에서는 필요 없더라도 터미네이터를 구현해야 합니다.
19. 상속 유형 위에 인터페이스를 정의하고 구현합니다
1. 관련 없는 타입은 공통 인터페이스를 공동으로 구현할 수 있으며, 상속보다 인터페이스를 구현하는 것이 더 쉽다; 2. 인터페이스는 비교적 안정적이며, 인터페이스 내 함수 집합을 다른 구현 계약처럼 캡슐화하며, 기본 클래스는 시간이 지남에 따라 확장될 수 있습니다.
20. 인터페이스 구현과 가상 메서드 재작성을 구분한다
1. 기본 클래스에서 인터페이스를 구현할 때, 파생 클래스는 기본 클래스 메서드 사용을 숨기기 위해 new를 사용해야 합니다; 2. 기본 클래스 인터페이스의 메서드는 가상 메서드로 선언된 후 파생 클래스에서 구현될 수 있습니다.
21. 재확인을 표현하기 위한 위임 사용
1. 위임자 자체는 예외 캡처를 제공하지 않으므로, 어떤 멀티캐스트 대리자 통화도 전체 통화 체인을 종료합니다. 2. 대리자 체인 내 각 위임 대상을 표시하고 호출함으로써, 멀티캐스트 대리자가 마지막 대의자의 출력만 반환하는 것을 방지할 수 있습니다.
22. 이벤트 사용으로 외부 인터페이스를 정의합니다
1. 공통 이벤트로 선언하고, 컴파일러가 추가와 재이동 메서드를 만들어야 합니다. 2. System.ComponentModel.EventHandlerList 컨테이너를 사용하여 각 이벤트 핸들러를 저장하고, 타입에 많은 이벤트가 포함될 경우 모든 이벤트의 복잡성을 숨깁니다.
23. 내부 클래스 객체에 대한 참조 반환을 피하세요
1. 값 타입 객체에 대한 접근이 객체의 복사본을 생성하므로, 값 타입 정의의 속성은 타입 객체 내부의 상태를 전혀 변경하지 않습니다; 2. 상수 타입은 객체의 상태 변경을 피할 수 있습니다; 3. 객체 내부 상태에 대한 손상을 최소화하기 위해 부분집합에 대한 접근을 제한하는 인터페이스를 정의합니다. 4. 다른 객체에 대한 접근을 제한하는 래퍼 객체를 정의합니다; 5. 고객 코드가 내부 데이터 요소를 변경할 때, 관찰자 모드를 구현하여 객체가 변경 사항을 검증하거나 대응할 수 있습니다.
24. 선언적 프로그래밍은 명령형 프로그래밍보다 낫다
여러 유사한 수작업 알고리즘에서 실수를 할 가능성을 방지할 수 있으며, 명확하고 읽기 쉬운 코드를 제공합니다.
25. 가능한 한 직렬화 가능한 타입을 구현합니다
1. 타입은 UI 컨트롤, 창 또는 폼을 나타내지 않으며, 직렬화를 지원해야 합니다; 2. NonSerializedAttribute의 deserialized 속성을 추가할 때, 기본값은 IDeserializationCallback을 구현하는 OnDeserialization() 메서드에서 로드할 수 있습니다; 3. 버전 관리에서는 ISerializable 인터페이스를 사용하여 유연한 제어를 할 수 있고, 스트림 내 데이터에 따라 객체를 초기화하는 직렬화 생성자를 제공할 수 있으며, 구현 시 SerializationFormatter 예외 권한도 필요합니다. 4. 파생 클래스를 생성해야 한다면, 파생 클래스에 대한 훅 메서드를 제공해야 합니다.
26. 정렬 관계를 구현하기 위해 IComparable 및 IComparer 인터페이스를 사용한다
1. IComparable 인터페이스는 타입에 대해 가장 자연스러운 정렬 관계를 구현하는 데 사용되며, 네 개의 비교 연산자를 오버로드하고, 특정 타입을 매개변수로 받아들일 수 있도록 CompareTo() 메서드의 과부하 버전을 제공합니다. 2. IComparer는 IComparable과 다른 정렬 관계를 제공하거나, 타입 자체가 구현되지 않았다고 명시하는 정렬 관계를 제공하는 데 사용됩니다.
27. ICloneable 인터페이스 피하기
1. 값 타입의 경우, ICloneable 인터페이스를 지원할 필요는 없고 기본 할당 연산만 사용하세요; 2. ICloneable 인터페이스를 지원해야 할 수 있는 기본 클래스의 경우, 이를 위한 보호 복제 생성자를 만들어야 하며, IConeable 인터페이스는 피해야 합니다.
28. 강제 변환 연산자 피하기
변환 연산자 대신 생성자를 사용하면 변환이 더 명확해지는데, 이는 변환 후 임시 객체가 사용되어 이상한 버그를 쉽게 유발할 수 있습니다.
29. 새로운 버전의 누적으로 문제가 발생할 때만 새로운 수정자를 고려하세요
30. CLS 호환 어셈블리를 가능한 한 많이 구현한다 1. 호환 가능한 어셈블리를 만들기 위해서는 두 가지 규칙을 따라야 합니다: 어셈블리의 모든 공공 및 보호 멤버가 사용하는 매개변수와 반환 값 유형이 CLS와 호환되어야 합니다; CLS와 호환되지 않는 공공 및 보호 회원은 반드시 CLS 호환 대안을 가져야 합니다; 2. 인터페이스를 명시적으로 구현함으로써 CLS 호환성 타입 검사를 우회할 수 있으며, CLSCompliantAttribute는 사설 멤버의 CLS 호환성을 검사하지 않습니다.
31. 가능한 한 짧고 간결한 방법을 구현하세요
1. JIT 컴파일러는 메서드 단위로 컴파일하며, 호출되지 않은 메서드는 JIT에 의해 컴파일되지 않습니다; 2. 더 긴 스위치에서 Case 문장의 코드를 한 번에 한 메서드씩 대체하면, JIT 컴파일러가 절약한 시간이 곱해집니다; 3. 짧고 간결한 방법과 적은 국소 변수 선택으로 최적화된 레지스터 사용을 얻을 수 있습니다; 4. 메서드 내 제어 분기가 적을수록 JIT 컴파일러가 변수를 레지스터에 넣는 것이 더 쉬워집니다.
32. 가능한 한 작고 높은 응집력 있는 조립체를 실현한다
1. 모든 공개 클래스와 공통 기본 클래스를 일부 어셈블리에 넣고, 공개 클래스에 함수를 제공하는 도구 클래스를 같은 어셈블리에 넣으며, 관련 공개 인터페이스를 별도의 어셈블리로 패키징하고, 마지막으로 애플리케이션 내 수평 위치에 있는 클래스를 처리합니다; 2. 원칙적으로 두 가지 유형의 부품을 만들어야 합니다: 하나는 특정 기능을 가진 작고 집계된 조립체이고, 다른 하나는 공통 기능을 가진 크고 넓은 조립체입니다.
33. 타입의 가시성 제한
1. 타입의 함수를 노출하는 인터페이스를 사용하면 내부 클래스를 생성하기 쉽게 하면서도 어셈블리 외부에서의 가용성을 제한할 수 있습니다; 2. 외부에 노출되는 공공 유형이 적을수록 향후 확장 및 변경 구현에 대한 선택지가 더 많아집니다.
34. 대규모 세분화된 웹 API 생성
이로 인해 기계 간 트랜잭션의 빈도와 부하가 최소화되어 대규모 작업과 세밀한 실행을 서버에 전달할 수 있습니다.
35. 재작성은 이벤트 프로세서보다 더 낫습니다
1. 이벤트 프로세서가 예외를 던지면 이벤트 체인의 다른 프로세서들은 호출되지 않지만, 재작성된 가상 메서드에는 이런 문제가 발생하지 않습니다. 2. 재작성은 전체 요청 목록을 반복해야 하므로 CPU 시간이 더 많은 연관 이벤트 프로세서보다 훨씬 효율적입니다. 3. 이벤트에 더 유연하게 대응할 수 있고, 동일한 이벤트에 여러 응답을 연관시킬 수 있습니다. 4. 일반적인 규칙은 파생 사건을 다루는 것이며, 재작성 방법이 더 낫습니다.
36. 공정 이용. .NET 런타임 진단
1. System.Diagnostics.Debug\Trace\EventLog는 프로그램이 런타임에 진단 정보를 추가하는 데 필요한 모든 도구를 제공하며, EventLog가 구성 요소를 제공할 때 애플리케이션이 시스템 이벤트 로그에 기록할 수 있습니다; 2. 마지막으로, 직접 진단 라이브러리를 작성하지 마세요. .NET FCL에는 이미 필요한 핵심 라이브러리가 있습니다.
37. 표준 구성 메커니즘 사용
1、. .NET 프레임워크의 System.Windows.Application 클래스는 공통 구성 경로를 설정할 수 있는 속성을 정의합니다; 2. Application.LocalAppDataPath와 Application.userDataPath는 로컬 데이터 디렉터리와 사용자 데이터의 경로 이름을 생성합니다; 3. ProgramFiles 및 Windows 시스템 디렉터리에 데이터를 쓰지 마세요. 이 위치들은 더 높은 보안 권한이 필요하며, 사용자가 쓰기 권한을 가질 것으로 기대하지 마세요.
38. 데이터 바인딩을 사용자 지정 및 지원
1. BindingMananger와 CurrencyManager의 두 객체는 컨트롤과 데이터 소스 간의 데이터 전송을 구현합니다; 2. 데이터 바인딩의 장점: 데이터 바인딩을 사용하는 것이 직접 코드를 작성하는 것보다 훨씬 간단합니다; 텍스트 데이터 항목 이외의 범위에도 사용해야 하며, 다른 디스플레이 속성도 바인딩할 수 있습니다; WindowOS Forms 데이터 바인딩의 경우, 검사 관련 데이터 소스의 다중 제어 동기화 처리 능력; 3. 객체가 필요한 속성을 지원하지 않을 때, 현재 객체를 차단한 후 원하는 객체를 추가하여 데이터 바인딩을 지원할 수 있습니다.
39. 사용. .NET 검증
1. ASP.NET 에는 유효성을 검증하는 다섯 개의 컨트롤이 있으며, CustomValidator를 사용해 새로운 클래스를 도출하여 자신만의 인증기를 추가할 수 있습니다. 2. Windows 검증은 이벤트 핸들러를 작성하기 위해 하위 System.Windows.Forms.Control.Validating を必要とし합니다.
40. 필요에 따라 적절한 **를 선택하세요
1. 배열에는 두 가지 명백한 결함이 있습니다: 동적으로 크기를 조절할 수 없다는 점; 크기 조정은 시간이 많이 걸립니다; 2. ArrayList는 1차원 배열과 연결 리스트의 특성을 혼합하며, Queue와 Stack은 배열을 기반으로 한 특수 배열입니다; 3. 프로그램이 항목을 추가하고 삭제하는 데 더 유연할 때, 더 견고한 타입을 만들 수 있고, **를 시뮬레이션하는 클래스를 만들 때는 인덱서와 IEnumberable 인터페이스를 구현해야 합니다.
41. DataSet은 커스텀 구조보다 낫습니다
1. 데이터셋에는 두 가지 단점이 있습니다: XML 직렬화 메커니즘을 사용하는 데이터셋과 non-.NET 코드 간의 상호작용이 좋지 않다는 점; DataSet은 매우 다재다능한 컨테이너입니다; 2. 강한 유형의 데이터셋은 더 많은 설계 규칙을 깨며, 자체 작성한 더 우아한 설계보다 개발 효율이 훨씬 높습니다.
42. 성찰을 단순화하기 위해 특성을 활용한다
개발자가 동적으로 사용 가능한 타입, 메서드, 속성을 선언하도록 강제하는 기능 클래스를 설계하고 구현함으로써, 애플리케이션 런타임 오류를 줄이고 소프트웨어 사용자 만족도를 높일 수 있습니다.
43. 반사 신경을 과도하게 사용하지 마세요
1. Invoke 멤버들이 사용하는 매개변수와 반환 값은 System.Object로, 런타임에 타입을 변환하지만, 문제 발생 가능성은 증가했습니다. 2. 인터페이스는 더 명확하고 유지보수 용이한 시스템을 제공하며, 반사는 매우 강력한 후기 결합 메커니즘입니다. .NET 프레임워크는 Windows 컨트롤과 웹 컨트롤에 데이터 바인딩을 구현하는 데 이를 사용합니다.
44. 애플리케이션에 대한 특정 예외 클래스 생성
1. 서로 다른 예외 클래스가 필요한 유일한 이유는 사용자가 캐치 프로세서를 작성할 때 서로 다른 오류에 대해 쉽게 다른 접근법을 취할 수 있게 하기 위함입니다; 2. 서로 다른 수리 동작이 있을 수 있을 때, 예외 기본 클래스가 지원하는 모든 구성자를 제공함으로써 애플리케이션에 완전한 기능 예외 클래스를 만들고, InnerException 속성을 사용해 하위 수준 오류 조건에서 생성된 모든 오류 정보를 저장할 수 있습니다.
45. 비정상 안전 보장에 우선순위를 두세요
1. 강한 예외 보장은 예외 복구와 간소화된 예외 처리 사이에서 최상의 균형을 제공하며, 예외로 인해 작업이 중단될 때도 프로그램 상태는 변하지 않습니다. 2. 수정할 데이터의 방어적 복사를 하여 방어적 복사본을 수정하고, 중간에 연산이 발생하면 예외가 발생할 수 있으며, 임시 복사본과 원본 객체가 교환됩니다; 3. 종료자, Dispose() 메서드, 그리고 데리게이트에 결합된 타겟 메서드는 어떤 상황에서도 예외를 던지지 않도록 해야 합니다.
46. 상호운용성 최소화
1. 상호운용성에는 세 가지 비용이 있습니다: 관리형 힙과 비관리 힙 간 데이터 열거 비용, 관리형 코드와 비관리 코드 간 전환 비용, 그리고 하이브리드 환경을 다루는 개발자들의 개발 작업; 2. 상호운용에서 블리터블 타입을 사용하면 객체의 내부 구조에 영향을 받지 않고 관리되지 않는 환경 간에 효과적으로 복제할 수 있습니다. 3. In/Out 기능을 사용하여 가장 적절하고 불필요한 다중 복제를 보장하고, 데이터 열거 방식을 선언하여 성능을 향상시킵니다. 4. COM Interoperation을 사용하여 COM 컴포넌트와의 상호운용성을 가장 간단하게 구현하거나, P/Invoke를 사용해 Win32 API를 호출하거나, C++ 컴파일러의 /CLR 스위치를 사용해 관리형과 비관리형 코드를 혼합합니다;
47. 안전 코드에 우선권을 부여한다
1. 관리되지 않은 메모리 접근을 가능한 한 피하며, 격리 저장소는 관리되는 코드와 신뢰할 수 있는 사용자의 접근을 막을 수 없습니다. 2. 어셈블리가 웹에서 실행될 때는 격리 저장소를 고려하고, 특정 알고리즘이 더 높은 보안 권한을 요구할 경우 해당 코드는 별도의 어셈블리에 격리되어야 합니다.
48. 관련 도구와 자원을 마스터하세요
1. NUnit을 사용하여 자동 단위 테스트를 구축(VS2010에 통합); 2. FXCop 도구는 어셈블리에서 IL 코드를 획득하고, 이기종 코딩 규칙과 모범 사례에 따라 분석한 후 최종적으로 위반 사항을 보고합니다. 3. ILDasm은 세부 사항에 대한 통찰을 얻는 데 도움을 주는 IL 디스어셈블 도구입니다; 4. 공유 소스 CLI는 .NET 프레임워크 커널과 C# 컴파일러를 포함하는 구현 소스 코드입니다. |