Unity 인터뷰 | (1) C# 기초 [종합 요약 | 지속적으로 업데이트]

목차

1. 객체지향의 세 가지 주요 특징
  • 상속: 열기 및 닫기 원칙에 따라 코드 재사용을 개선하고 소프트웨어 유지 관리성을 향상시키는 중요한 수단입니다. 상속의 주요 기능은 하위 클래스의 공용 속성을 수집하여 공동으로 관리하고 보다 편리하게 사용할 수 있도록 하는 것입니다. 상속을 사용한다는 것은 하위 클래스가 몇 가지 공통 특성을 갖는다는 데 동의한다는 의미이므로 이러한 공통 특성을 추출하여 상위 클래스로 설정합니다. 상속의 전이성: 전이 메커니즘 a►b, b►c, c는 a의 속성을 갖습니다. 상속의 단일 루트 특성: C#에서 클래스는 하나의 클래스만 상속할 수 있으며 여러 부모 클래스를 가질 수 없습니다.
  • 캡슐화: 캡슐화는 데이터와 동작을 결합하고 동작을 통해 코드에 의한 데이터 수정 정도를 제한하며 데이터의 보안을 강화합니다. 속성은 C# 캡슐화 구현의 가장 좋은 구현입니다. 다른 사람들이 사용할 수 있도록 일부 복잡한 로직을 패키징하는 것은 매우 편리합니다. 다른 사람들은 그것이 어떻게 구현되는지 이해할 필요가 없습니다. 필요한 매개변수만 전달하면 원하는 결과를 얻을 수 있습니다. 캡슐화의 의미는 코드(데이터)가 실수로 파괴되는 것을 방지하거나 방지하는 것입니다.
  • 다형성(Polymorphism): 다형성은 동일한 이름을 가진 메소드가 다른 환경에서 다르게 적응적으로 반응할 수 있음을 의미하며 메소드를 동적으로 표시하는 중요한 수단입니다. 다형성은 객체가 여러 상태를 가지며 하위 클래스 객체를 상위 유형의 변수에 할당할 수 있음을 의미합니다.
2. 값 유형과 참조 유형을 간략하게 설명합니다.
  • 소개하다
    • 값 유형: 모든 단순 유형(정수, 부동 소수점, bool, char), struct, enum을 포함합니다.
      System.ValueTyoe에서 상속됨

    • 참조 유형에는 System.Object에서 상속된 문자열, 개체, 클래스, 인터페이스, 대리자 및 배열이 포함됩니다.
  • 차이점
    • 값 유형은 메모리 스택에 저장되고, 참조 유형 데이터는 메모리 힙에 저장되며, 메모리 장치는 힙에 저장된 주소를 저장합니다.
    • 값 유형 액세스는 빠른 반면 참조 유형 액세스는 느립니다.
    • 값 유형은 실제 데이터를 나타내고 참조 유형은 메모리 힙에 저장된 데이터에 대한 포인터 및 참조를 나타냅니다.
    • 스택 메모리는 자동으로 해제되고, 힙 메모리는 .NET의 GC에 의해 자동으로 해제됩니다.
    • 값 유형은 System.ValueType에서 상속되고 참조 유형은 System.Object에서 상속됩니다.
    • 값 유형은 직접 값을 스택에 저장하고, 참조 유형 데이터 자체는 힙에 있으며, 스택에 저장되는 것은 참조의 주소입니다.
3. 오버로딩과 재작성의 차이점
  • 캡슐화, 상속, 다형성은 위치가 다르며 오버로딩은 동일한 클래스에 있고 재작성은 부모 클래스와 자식 클래스에 있습니다.
    • 정의 메소드가 다르고, 오버로드된 메소드 이름과 매개변수 목록이 다르며, 오버라이드된 메소드 이름과 매개변수 목록이 동일합니다.
    • 호출 방법은 다릅니다. 오버로드는 동일한 개체를 사용하여 다른 매개변수로 호출하고, 재정의는 다른 개체를 사용하여 동일한 매개변수로 호출합니다.
    • 다형성의 시기는 다릅니다. 오버로딩은 컴파일 타임 다형성이고 오버라이딩은 런타임 다형성입니다.
4.C#의 모든 참조 유형의 기본 클래스는 무엇입니까?
  • 참조 유형의 기본 클래스는 System.Object이고 값 유형의 기본 클래스는 System.ValueType입니다.
    동시에 값 형식도 System.Object에서 암시적으로 상속됩니다.
5. ArrayList와 List의 주요 차이점을 간략하게 설명해주세요.
  • 일반 데이터 유형이 없는 ArrayList가 누락되었습니다.
  • 일반 데이터 유형의 목록은 손실되지 않습니다.
  • ArrayList에는 boxing 및 unboxing이 필요하지만 List는 필요하지 않습니다.
  • ArrayList에는 안전하지 않은 유형이 있습니다(ArrayList는 여기에 삽입된 모든 데이터를 객체로 처리합니다) 박싱 및 언박싱 작업(시간이 많이 소요됨) IList는 인터페이스이고 ArrayList는 이 인터페이스를 구현하고 인스턴스화할 수 있는 클래스입니다.
  • List 클래스는 ArrayList 클래스와 일반적으로 동일합니다. List 클래스도 IList 인터페이스를 상속하므로 사용법의 대부분은 ArrayList와 유사합니다. 가장 중요한 차이점은 List 컬렉션을 선언할 때 List 컬렉션에 있는 데이터의 개체 유형도 선언해야 한다는 것입니다.
6.GC 관련 지식 포인트
  • GC의 개념
    • C#에는 힙 메모리와 스택 메모리라는 두 가지 메모리 관리 풀이 있습니다. 스택 메모리(Stack)는 주로 작고 짧은 데이터를 저장하는 데 사용되고, 힙 메모리(Heap)는 더 크고 오래 지속되는 데이터를 저장하는 데 주로 사용됩니다. C#의 변수는 스택 또는 힙 메모리에만 메모리를 할당하며, 변수는 스택 메모리 또는 힙 메모리에 저장됩니다.
      변수가 활성화되어 있는 한 변수가 차지하는 메모리는 사용된 것으로 표시되고 메모리의 이 부분이 할당됩니다.
      변수가 더 이상 활성화되지 않으면 변수가 차지하는 메모리는 더 이상 필요하지 않으며, 이 메모리 부분은 메모리 풀로 재활용되어 다시 사용될 수 있습니다.이 작업이 메모리 재활용입니다. 스택의 메모리는 매우 빠르게 재활용되지만 힙의 메모리는 제때에 재활용되지 않으므로 해당 메모리는 여전히 사용된 것으로 표시됩니다. 더 이상 사용되지 않는 메모리는 GC 중에만 회수됩니다.
      가비지 수집은 주로 힙에서의 메모리 할당 및 재활용을 의미하며, C#에서는 GC 작업이 힙 메모리에서 정기적으로 수행됩니다.
  • GC로 인한 문제
    • 게임 성능: GC 작업은 이벤트 소모가 매우 많은 작업입니다. 힙 메모리에 변수나 참조가 많을수록 순회 확인 작업이 느려지고 게임 실행 속도가 느려집니다. 예를 들어 CPU가 중요한 순간에 있을 때 게임 성능을 위해 One 작업을 수행하면 게임 프레임 속도가 떨어지게 되어 큰 영향을 미칩니다.
    • 게임 메모리: (unityGC는 비세대, 비압축 표시 및 지우기 알고리즘을 사용합니다.) GC 작업은 "메모리 조각화"를 유발합니다. 힙에서 메모리 단위가 할당되면 그 크기는 저장 변수의 크기에 따라 달라집니다. 힙에서 메모리가 회수되면 힙 메모리가 조각난 단위로 분할될 수 있습니다. (즉, 전체 용량은 고정되어 있지만 단위 메모리가 작다. 예를 들어 집은 크고 방은 작아서 적당한 방을 찾을 수 없다.) 즉, 적당한 저장 장치를 마련하지 못하는 경우이다. 다음 할당 중에 발견되면 GC 작업이 트리거되거나 힙 메모리 확장 작업이 발생하여 GC가 자주 발생하고 게임 메모리가 증가합니다.
  • GC 트리거 타이밍
    • 메모리 할당 작업은 힙 메모리에서 수행되며, 메모리가 충분하지 않을 경우 가비지 수집이 실행되어 유휴 메모리를 활용합니다.
      GC가 자동으로 실행되어 다양한 플랫폼이 서로 다른 빈도로 실행되며
      GC가 강제로 실행될 수 있습니다.
  • GC를 피하는 방법은 무엇입니까?
    • 임시 변수의 사용을 줄이고, 더 많은 공용 개체를 사용하고, 캐싱 메커니즘을 더 많이 활용하세요. (함수 외부에서 컨테이너를 정의하고, 컨테이너 사용 시 수정하세요.)
      새로운 객체 수를 줄이세요.
    • 많은 수의 문자열을 연결할 때는 String 대신 StringBuilder를 사용하세요. (문자열은 수정할 수 없습니다. 수정이란 새로운 문자열 객체를 생성하는 것을 의미합니다. 오래된 것은 직접 버리고 GC를 기다립니다. 그러나 소수의 문자열이 문자열로 이어져 있어 성능은 stringbuilder보다 좋습니다)
    • List, StringBuilder 등의 확장 컨테이너를 사용하는 경우 정의 시 저장되는 변수의 메모리 크기에 따라 저장 공간을 정의하여 확장 작업을 줄여보세요. (확장 후에는 기존 컨테이너를 바로 버리고 GC를 기다립니다)
    • 코드 로직 최적화: 예를 들어 텍스트는 프레임마다 수정하는 대신 타이머가 1초를 초과할 때만 수정되거나 중요한 순간에 GC가 금지되어 게임 성능에 영향을 미칠 수 있습니다. 페이지 또는 진행률 표시줄.
    • 객체 풀 활용: 객체 풀은 Unity에서 자주 사용하는 메모리 관리 서비스로, 총알, 몬스터 등 자주 사라지는 객체에 대해 각 객체를 생성하는 시스템 오버헤드를 줄이는 데 사용됩니다. 객체를 제거하고 싶을 때는 직접 Destory하지 않고 SetActive(false)로 숨겨서 풀에 넣고, 다시 새로운 객체를 표시해야 할 때는 먼저 풀에 가서 있는지 확인합니다. 숨겨진 객체가 있으면 제거하고 (표시) SetActive(true)가 없으면 다시 인스턴스화합니다.
    • 박싱 및 언박싱 감소(박싱은 값 유형을 객체 유형 또는 이 값 유형에 의해 구현된 인터페이스 유형으로 변환하는 프로세스입니다.)
    • 코루틴: yeild return 0은 박싱 및 언박싱을 생성하며, 이는 yeild return null로 대체될 수 있습니다.
7. 구조와 클래스
  • 구조와 클래스의 차이점:

    • 구조체는 값 유형이고 클래스는 참조 유형입니다.
    • 구조체는 스택에 저장되고 클래스는 힙에 저장됩니다.
    • 구조체 변수와 클래스 객체를 타입 전달하는 경우에는 구조체 변수는 값으로 전달하고, 클래스 객체는 참조로 전달하거나 포인터를 전달하는 방식으로 함수 내에서 매개변수 값이 변경되면 구조체의 값이 객체는 변경되지 않고 그대로 유지되지만 클래스 객체의 값은 변경됩니다.
    • C#에서는 구조체 타입을 정의할 때 멤버를 초기화할 수 없기 때문에 구조체 변수를 정의할 때 변수의 모든 멤버를 스스로 할당하고 초기화해야 한다. 하지만 클래스의 경우 클래스를 정의할 때 멤버 변수를 초기화할 수 있으므로 객체를 정의할 때 객체 자체에는 이미 초기값이 있고 개별 변수를 직접 다시 할당할 수 있습니다. (C++에서는 클래스 정의에서 초기화를 수행할 수 없으며 초기화는 생성자에 배치되어야 합니다.)
    • 구조체는 매개변수 없는 생성자를 선언할 수 없지만 클래스는 가능합니다.
      구조체 유형을 선언한 후 new 연산자를 사용하여 생성된 객체를 만들거나 new 키워드를 사용할 수 없습니다. new를 사용하지 않으면 필드는 할당되지 않은 상태로 유지되며 모든 필드가 초기화될 때까지 객체를 사용할 수 없습니다.
    • 구조체가 매개 변수가 있는 생성자를 선언한 후에는 매개 변수가 없는 생성자가 차단되지 않습니다.
    • 구조체는 소멸자를 선언할 수 없지만 클래스는 선언할 수 있습니다.
    • 구조는 상속될 수 없지만 클래스는 상속될 수 있습니다.
    • 구조체는 생성자의 모든 멤버 변수를 초기화해야 하지만 클래스는 선택적으로 초기화합니다.
    • 구조는 정적으로 수정할 수 없지만(정적 구조는 존재하지 않음) 클래스는 가능합니다.
  • 사용 시나리오

    • 스택의 값형 구조로 스택의 접근 속도는 힙에 비해 빠르지만 용량이 작아 포인트, 직사각형, 컬러 등 가벼운 객체에 적합하다.
    • 객체가 데이터 모음인 경우 구조(위치, 좌표)를 연결하는 것이 우선인데,
      변수에 값을 전달할 때 객체의 참조 주소 대신 객체의 복사본을 전달하고 싶은데, 이 경우 , 구조를 사용할 수 있습니다.
      친절한:
    • 클래스는 참조형으로 힙에 저장되며, 힙은 용량이 크고 중량물에 적합하며, 스택 공간이 크지 않고 힙에 대응되는 항목이 많아야 한다.
    • 객체에 상속 및 다형성 기능이 필요한 경우 클래스(플레이어, 몬스터)를 사용하세요.
8.C#의 네 가지 액세스 한정자는 무엇인가요? 차이점이 뭐야?
  • 속성 수정자, 액세스 수정자, 클래스 수정자, 멤버 수정자
  • 속성 수정자:
    • 직렬화 가능: 값을 기준으로 개체를 원격 서버로 마샬링합니다.
    • STATread: 단일 스레드 제품군을 의미하며 스레드 모델입니다.
    • MATAThread: 멀티 스레드 제품군을 의미하며 스레드 모델이기도 합니다
      .
  • 액세스 수정자:
    • 공개: 무제한 액세스.
    • private: 멤버가 포함된 클래스만 액세스할 수 있습니다.
    • 내부: 현재 프로젝트만 접근할 수 있습니다.
    • protected: 멤버 및 파생 클래스를 포함하는 클래스만 액세스할 수 있습니다
      .
  • 클래스 수정자:
    • abstract: 추상 클래스. 클래스가
      다른 클래스의 기본 클래스로만 사용될 수 있음을 나타냅니다.
    • 봉인됨: 봉인된 클래스입니다. 클래스를 상속받을 수 없음을 나타냅니다. 물론
      봉인된 클래스는 동시에 추상 클래스일 수 없습니다. 추상화는 항상
      상속되기를 원하기 때문입니다.
  • 멤버 수정자:
    • abstract: 메서드나 속성이 구현되지 않았음을 나타냅니다.
    • 밀봉: 밀봉 방식. 이렇게 하면 파생 클래스에서 이 메서드를 호출할 수 없습니다.
    • 재정의(᯿ 포함). 클래스의 모든 멤버 메서드를
      봉인된 메서드로 사용할 수 있는 것은 아니며, 기본 클래스의 가상 메서드를 로드하고
      특정 구현 메서드를 제공해야 합니다. 따라서 메소드 선언에서
    • 봉인된 수정자는 항상 재정의 수정자와 함께 사용됩니다.
    • 대의원: 대의원. 함수 포인터를 정의하는 데 사용됩니다. C#의 이벤트 드라이버는
      대리자 + 이벤트를 기반으로 합니다.
    • const: 이 멤버의 값이 읽기 전용이고 수정이 허용되지 않음을 지정합니다.
    • 이벤트: 이벤트를 선언합니다.
    • extern: 메소드가 외부에서 구현됨을 나타냅니다.
    • override: ᯿가 쓰여집니다. 기본 클래스에서 상속된 멤버의 새로운 구현입니다.
    • readonly: 필드가
      선언되고 동일한 클래스 내에서만 값이 할당될 수 있음을 나타냅니다.
    • static: 멤버가 특정 개체가 아닌 형식 자체에 속함을 나타냅니다
      . 즉, 정의 후 인스턴스화 없이 사용이 가능하다.
    • virtual: 상속된 클래스에서 메서드나 접근자의 구현을
      재정의할 수 있음을 나타냅니다.
    • new: 재정의 기능을 달성하려면 파생 클래스에서 지정된 기본 클래스 멤버를 숨깁니다
      . 상속된 클래스의 멤버를 숨기려면
      파생 클래스에서 동일한 이름으로 멤버를 선언하고 new 수정자로 수정합니다.
9. 수정자에 대한 간략한 설명: 개인, 공개, 보호 및 내부의 차이점
  • 공개: 모든 클래스 및 회원에게 공개, 무제한 액세스
  • private: 이 클래스에만 공개됩니다.
  • protected: 이 클래스 및 해당 파생 클래스에 공개
  • 내부: 클래스가 포함된 어셈블리에서만 클래스에 액세스할 수 있습니다.
  • 내부 보호: 보호 + 내부
10.힙과 스택의 차이점은 무엇인가요?
  • 일반적으로 코드 세그먼트 1의 AddFive() 메서드, int pValue 변수, int result 변수 등과 같은 코드 실행 단계를 저장합니다. 힙에 저장되는 것은 대부분 객체, 데이터 등입니다. (번역자 주: 컴파일러 최적화 무시) 스택을 상자가 차례로 쌓인 것으로 생각할 수 있습니다. 우리는 사용할 때 상단에서 한 상자씩 제거합니다.
    스택의 경우에도 마찬가지인데, 메서드(또는 유형)가 호출되면 스택의 최상위(프레임, 번역 주석: 호출 프레임이라고 함)에서 가져와서 다음 항목을 가져옵니다. 힙은 우리가 사용하는 다양한 객체와 기타 정보를 저장하는 창고와도 같으며, 스택과 달리 호출된 후 바로 지워지지 않습니다.
  • GC 측면에서 보면 스택은 선입후출 원칙을 유지하며 시스템에 의해 자동으로 할당 및 유지되는 연속적인 메모리 도메인이며, 생성된 가비지는 시스템에 의해 자동으로 해제됩니다. 힙은 순서가 없고, 사용자가 제어하고 해제하는 불연속적인 메모리 도메인으로, 사용자가 직접 해제하지 않으면 메모리가 특정 값에 도달하면 가비지 컬렉터(GC)에 의해 재활용됩니다.
  • 저장: 스택은 일반적으로 메소드 변수 등과 같은 코드 실행 단계를 저장합니다. 힙에 저장되는 것은 대부분 객체, 데이터 등입니다. 스택은 상자가 하나씩 쌓여 있는 것으로 생각할 수 있습니다(메모리 주소가 높을수록 낮음). 이를 사용할 때마다 맨 위에서 상자 하나를 가져오고, 메서드(또는 유형)가 호출되어 완료되면 스택 맨 위에서 다음 상자를 가져옵니다. 힙은 우리가 사용하는 다양한 객체와 기타 정보를 저장하는 창고와도 같으며, 스택과 달리 호출된 후 바로 지워지지 않습니다.
  • 캐싱: 스택은 일반적으로 호출 시 저장 공간에 있다가 호출이 완료되면 즉시 해제되는 1단계 캐시를 사용하며, 힙은 2단계 캐시에 저장되며 가비지에 의해 수명 주기가 결정됩니다. 가상 머신의 수집 알고리즘(고아 객체가 되면 재활용할 수 없음) 따라서 이러한 개체를 호출하는 속도는 상대적으로 느립니다.
  • 저장공간: 스택은 선입후출 방식의 데이터 구조로, 메모리에서는 연산을 위해 변수가 스택에 할당됩니다. 힙은 참조형의 인스턴스(객체)를 위한 공간을 할당하는 데 사용되는 메모리 영역으로, 힙에 객체를 생성하면 객체의 주소가 스택의 변수에 전달됩니다. 또는 변수가 이 객체를 참조함)---즉, 스택의 변수는 힙의 주소가 XXX인 인스턴스(객체)를 가리킵니다.
11. 정적 생성자
  • 정적 생성자에는 액세스 한정자나 매개변수가 없습니다.
  • .NET에서는 첫 번째 클래스 인스턴스가 생성되거나 정적 멤버가 참조될 때 자동으로 정적 생성자를 호출하여 클래스를 초기화합니다.
    클래스에는 정적 생성자가 하나만 있을 수 있습니다.
  • 매개변수 없는 생성자는 정적 생성자와 공존할 수 있습니다.
  • 최대 한 번 실행합니다.
  • 정적 생성자는 상속될 수 없습니다.
  • 정적 생성자가 작성되지 않고 클래스에 초기 값 설정이 있는 정적 멤버가 포함되어 있는 경우 컴파일러는 자동으로 기본 정적 생성자를 생성합니다.
  • 정적 생성자가 예외를 throw하는 경우 런타임은 생성자를 다시 호출하지 않으며 프로그램이 실행 중인 애플리케이션 도메인의 수명 동안 형식이 초기화되지 않은 상태로 유지됩니다.
  • 클래스 생성자 앞에 static을 추가하면 어떤 오류가 보고되며, 그 이유는 무엇입니까?
  • 생성자의 형식은 public + 클래스명이며, static을 추가하면 오류가 발생합니다(정적 생성자는 유형 객체에 접근할 수 없으며 정적 생성자는 한 번만 실행됩니다.
  • 런타임이 클래스 인스턴스를 만들거나 처음으로 정적 멤버에 액세스하기 전에 런타임은 정적 생성자를 호출합니다.
  • 정적 생성자는 인스턴스 수준 생성자보다 먼저 실행됩니다.
  • 분명히 this와 base를 사용하여 생성자를 호출할 수는 없습니다.
  • 클래스는 하나의 정적 함수만 가질 수 있으며 정적 변수가 있는 경우 시스템은 자동으로 정적 함수를 생성합니다.
12. stringBuilder 유형에 비해 C# 문자열 유형의 장점은 무엇입니까?
  • 문자열을 처리하는 경우 문자열에서 메서드를 사용할 때마다 새 문자열 객체를 생성하고 새 메모리 주소를 할당해야 하는 반면, stringBuilder는 원래 메모리의 문자열을 수정하므로 문자열 처리 측면에서는 여전히 권장됩니다. 메모리를 절약하려면 stringBuilder를 사용하세요. 그러나 문자열 클래스의 메서드와 함수는 여전히 stringBuilder 클래스보다 강력합니다.
  • 문자열 클래스는 불변이므로(즉, 문자열 개체를 변경하면 실제로 문자열 클래스의 다른 개체가 생성됨) 문자열 클래스 개체를 자주 변경해야 하는 경우에는 StringBuilder 클래스를 사용하는 것이 좋습니다. 클래스의 방법은 먼저 메모리에 일정 크기의 메모리 공간을 열어주는 것으로, StringBuilder 클래스 객체가 변경될 때 메모리 공간이 부족하면 객체를 다시 생성하는 대신 메모리 공간을 확장한다. 이렇게 하면 문자열 객체를 자주 연산할 때 메모리 낭비가 크게 발생하지 않으며 실제로 본질적으로는 큰 차이가 없으며 둘 다 문자열을 저장하고 연산하는 데 사용되며 유일한 차이점은 성능입니다.
  • String은 주로 공개 API에 사용되며 활용도가 높고 사용 범위가 넓으며 읽기 성능이 뛰어나고 메모리 사용량이 적습니다.
  • StringBuilder는 주로 문자열을 연결하는 데 사용되며 수정 성능이 좋습니다.
    하지만 현재 컴파일러에서는 String의 + 연산을 StringBuilder로 최적화했기 때문에 일반적으로 String을 사용할 수 있습니다.
  • 문자열은 불변이므로 스레드 동기화는 자연스럽습니다.
  • StringBuilder는 변경 가능하며 스레드가 아닌 동기화됩니다.
13. Lambda 표현식을 사용하여 C# 함수 Func(문자열 a, 문자열 b)를 작성하는 방법은 무엇입니까?
  • (a,b) => {};
14.가상함수 구현원리
  • 각 가상 기능에는 해당 가상 기능 테이블이 있으며, 가상 기능 테이블의 핵심은 각 개체의 가상 기능 항목 주소를 저장하는 포인터 배열입니다. 파생 클래스의 경우 기본 클래스의 가상 함수 테이블을 상속하고 자체 가상 함수 항목 주소를 추가합니다. 파생 클래스가 기본 클래스의 가상 함수를 재정의하면 상속된 가상 함수 항목 주소가 파생 클래스의 가상 함수 항목 주소로 대체됩니다. 가상 기능 테이블 대신 가상 기능 항목 주소를 다시 작성하세요.
    그런 다음 프로그램이 실행 중일 때 동적 바인딩이 발생하여 부모 클래스 포인터를 인스턴스화된 개체에 바인딩하여 다형성을 달성합니다.
15. 포인터와 참조의 차이점
  • 참조는 null일 수 없습니다. 즉, null 개체에 대한 참조가 없으며 포인터는 null(null 개체를 가리키는)일 수 있습니다.
  • 참조는 참조하는 객체를 지정하기 위해 초기화되어야 하며, 포인터는 그럴 필요가 없습니다.
  • 참조는 초기화 후에 변경할 수 없지만 포인터는 참조하는 개체의 값을 변경할 수 있습니다.
  • 참조로 객체에 접근하는 것은 직접 접근이고, 포인터로 객체에 접근하는 것은 간접 접근이다.
  • 참조의 크기는 참조된 객체의 크기이고, 포인터의 크기는 포인터 자체의 크기이며 일반적으로 4바이트입니다.
  • 참조는 const가 아니고 포인터는 const입니다.
  • 참조와 포인터에 대한 + 증분 연산자는 다른 의미를 갖습니다.
  • 참조는 메모리 공간을 할당할 필요가 없지만 포인터는 할당합니다.
16. C#에서 일반적으로 사용되는 컨테이너 클래스는 무엇이며 그 특징은 무엇입니까?
  • 리스트,해시테이블,사전,스택,큐
  • 스택 스택: 선입, 후출, 푸시 및 팝핑, 기본 일반 배열 구현, 스택의 2배 동적 확장
  • 대기열 대기열: 선입선출, 대기열 추가 및 대기열 제거, 기본 일반 배열 구현, 테이블 헤드 및 꼬리 포인터, 비어 있는지 또는 가득 차 있는지 여부는 크기 비교에 의해 결정됩니다.
  • 큐와 스택은 주로 임시 정보를 저장하는 데 사용됩니다.
  • 배열 배열: 길이를 선언해야 하며 안전하지 않습니다.
  • ArrayList 배열 목록: 배열을 동적으로 늘리고 안전하지 않으며 IList 인터페이스를 구현합니다(인덱스에 따라 액세스할 수 있는 제네릭이 아닌 컬렉션 개체를 나타냄). 개체 배열 구현
  • 목록 목록: 기본 구현은 일반 배열, 기능, 동적 확장 및 일반 안전성입니다.
    일반 배열에 일반 데이터(값 유형의 경우 데이터 자체, 참조 유형의 경우 참조)를 저장하고 요소를 추가합니다. 현재 일반 배열 용량을 초과하면 용량이 2배로 확장되어 목록 크기가 동적으로 변경됩니다. (참고: 크기는 개수가 아닌 용량을 나타냅니다.)
  • LinkList 연결리스트
    • 1. Array, List, ArrayList 컬렉션은 모두 큰 결함이 있는데, 즉 배열의 중간에서 요소를 삭제하거나 삽입하려면 비용이 많이 든다. 어레이에 추가되었습니다. 프런트 엔드가 이동합니다.
    • 2. LinkedList(하위 레이어는 연결리스트로 구현됨)는 연결리스트 기반의 데이터 구조로, 배열의 길이를 동적으로 확장할 필요 없이 배열 삭제 및 삽입의 효율성이 낮은 문제를 효과적으로 해결합니다.
    • 3. LinkedList의 장점: 요소 삽입 및 삭제가 상대적으로 효율적이지만, 단점: 액세스 효율성이 상대적으로 낮습니다.
      HashTable 해시 테이블(해시 테이블)
    • 개념: 가변 길이의 바이너리 데이터는 해시 함수를 통해 더 짧은 바이너리 데이터 세트에 매핑됩니다. 즉, Key는 HashFunction 함수를 통해 HashCode를 얻습니다.
    • 채우기 요소: α=n/m=0.72, 저장된 데이터 N 및 공간 크기 M
    • 그런 다음 해시 버킷 알고리즘을 통해 HashCode를 세그먼트로 나누고 각 세그먼트는 버킷 구조이며 HashCode는 일반적으로 나머지를 직접 가져옵니다.
    • 버킷 구조는 충돌을 악화시키므로 지퍼 방식을 사용하여 충돌 해결 충돌 요소의 단일 연결 목록을 생성하고 헤드 포인터 주소를 해당 버킷 위치에 해시 테이블에 저장합니다. 이렇게 해시 테이블 버킷의 위치를 ​​찾은 후, 단일 연결 리스트를 순회하여 해당 요소를 찾을 수 있습니다.
      1. 키-값 양식 액세스, 순서가 지정되지 않음, Object 유형, 유형 변환이 필요합니다.
      2. Hashtable 질의 속도는 빠르지만, 추가 속도가 상대적으로 느림
      3. Hashtable의 데이터는 실제로 내부 데이터 버킷(버킷 구조 배열)에 고정된 용량으로 저장되며, 배열에 따라 값을 구함 색인.
//哈希表结构体
private struct bucket {
    
    
   public Object key;//键
    public Object val;//值
    public int hash_col;//哈希码
}
//字典结构体
private struct Entry {
    
    
    public int hashCode;    // 除符号位以外的31位hashCode值, 如果该Entry没有被使用,那么为-1
    public int next;        // 下一个元素的下标索引,如果没有下一个就为-1
    public TKey key;        // 存放元素的键
    public TValue value;    // 存放元素的值
}
private int[] buckets;      // Hash桶
private Entry[] entries;    // Entry数组,存放元素
private int count;          // 当前entries的index位置
private int version;        // 当前版本,防止迭代过程中集合被更改
private int freeList;       // 被删除Entry在entries中的下标index,这个位置是空闲的
private int freeCount;      // 有多少个被删除的Entry,有多少个空闲的位置
private IEqualityComparer<TKey> comparer;   // 比较器
private KeyCollection keys;     // 存放Key的集合
private ValueCollection values;     // 存放Value的集合
  • 성능 순위:
    • 삽입 성능: LinkedList > Dictionary > HashTable > List
    • 순회 성능: 목록 > LinkedList > 사전 > HashTable
    • 속성 삭제: Dictionary > LinkedList > HashTable > List
17.C#에서 일반 컨테이너와 일반 컨테이너의 차이점은 무엇이며, 어느 것이 더 효율적인가요?
  • 제네릭이 없는 컨테이너에는 느린 박싱 및 언박싱 작업이 필요하므로 일반 컨테이너가 더 효율적이고 데이터 유형이 더 안전합니다.
18.일반적인 숫자 클래스는 무엇입니까?
  • 단순 값 유형: 정수 유형, 실수 유형, 문자 유형 및 부울 유형 포함
  • 복합 값 유형: 구조 유형 및 열거 유형 포함
19.제네릭이란 무엇입니까?
  • [다른 데이터 유형]에 대해 여러 코드가 [동일한 명령]을 실행하는 상황
  • Generics: 여러 유형이 코드 세트를 공유합니다.
    Generics는 유형 매개변수화를 허용합니다. Generic 유형은 유형에 대한 템플릿입니다.
  • 제네릭의 5가지 유형: 클래스, 구조체, 인터페이스, 델리게이트, 메소드
    제네릭을 나타내는 자리 표시자 T 입력 제네릭
    클래스는 실제 클래스가 아니지만 클래스의 템플릿
    제네릭 유형에서 인스턴스 생성
    [ 실제 유형】생성자 유형 생성》을 제공하여 제네릭 유형 선언 생성된 유형의 인스턴스
    Class<T1,T2> 일반 유형 매개변수
  • 성능: 제네릭은 값 유형의 박싱 및 언박싱 또는 참조 유형의 다운캐스팅을 강제하지 않으므로 성능이 향상됩니다.
  • 안전성: 제네릭을 사용하여 정의된 변수의 유형 제한을 알면 컴파일러는 유형 가정을 어느 정도 확인할 수 있으므로 제네릭은 프로그램의 유형 안전성을 향상시킵니다.
20.C#에서 unsafe 키워드는 무엇에 사용되나요? 언제 사용되나요?
  • 이 키워드는 비관리 코드에만 필요하며 일반적으로 포인터 작업이 있는 상황에서 사용됩니다.
  • 프로젝트 백팩 시스템의 임무장비 컬럼을 사용합니다.
21.C#에서 ref 키워드와 out 키워드의 차이점은 무엇인가요?
  • ref는 참조 매개변수를 수정합니다. 매개 변수에는 값이 할당되어야 하며 내부적으로 변경되거나 변경되지 않을 수 있으며 반환 값이 다시 가져오고 들어오고 나갑니다.
  • out은 출력 매개변수를 수정합니다. 매개변수에는 값이 할당될 수 없으며 값은 내부적으로 수정되어야 하며 반환 값을 다시 가져오기 전에 값을 명시적으로 할당해야 합니다.
  • 참조 매개변수 및 출력 매개변수는 새 저장 위치를 ​​생성하지 않습니다.
  • ref 매개변수가 값 유형인 경우 메소드의 데이터가 변경되면 원래 값 유형 데이터도 변경됩니다.
  • ref 매개변수 값이 유형을 참조하는 경우 원래 객체 힙의 데이터는 메소드에서 재할당된 후 변경됩니다. 참조 유형에 대해 새 객체가 생성되고 ref 매개변수에 할당되면 참조 주소는 새 객체를 가리킵니다. 개체 힙 데이터를 다시 확인합니다. 형식 매개변수와 새 개체는 메서드가 끝나면 사라집니다. 실제 매개변수는 여전히 원래 개체를 가리키고 있으며 값이 충분하지 않습니다. 데이터가 변경되었습니다.
22. For, foreach, Enumerator.MoveNext 사용 및 메모리 소비
  • for 루프는 인덱스별로 순차적으로 순회할 수 있고, foreach와 Enumerator.MoveNext는 반복적으로 순회할 수 있습니다. 메모리 소비에는 본질적으로 큰 차이가 없습니다.
  • 그러나 Unity의 업데이트에서는 일반적으로 foreach를 사용하는 것이 메모리 가비지를 남기므로 사용하지 않는 것이 좋습니다.
23. foreach 반복자 순회와 for 루프 순회 간의 차이점
  • 컬렉션에 각 순회가 필요한 경우 이것이 가능합니까? 특정 문제가 있습니다.
  • foreach의 반복 변수 항목은 읽기 전용이며 list.Remove(item) 작업과 같이 수정할 수 없습니다.
  • foreach가 읽기 전용일 때 기록하고 그 기록에 대해 작업하거나 직접 for 루프를 사용하여 순회합니다.
  • int[] 배열의 foreach 루프는 ArrayList 순회를 피하기 위해 더 이상 GC를 생성하지 않습니다.
  • for 문에서 초기화된 변수 i의 범위는 루프 본문 내부에서 볼 수 있습니다. 인덱스를 순회하면 인덱스를 기준으로 순회된 컬렉션을 수정할 수 있으므로 Unity의 for 루프에서 람다 식을 사용할 때 클로저 문제에 주의하세요.
  • foreach 순회 원리
    • 모든 컬렉션 클래스(Array) 개체에는 반복기 IEnumerator 인터페이스를 구현하는 개체를 반환할 수 있는 GetEnumerator() 메서드가 있습니다.
      반환된 IEnumerator 개체는 컬렉션 클래스 개체도 아니고 컬렉션의 요소 클래스 개체도 아니며, 독립적인 클래스 개체입니다.
    • 이를 통해 IEnumerator 인터페이스 객체 A가 구현되고, 컬렉션 클래스 객체의 각 요소 객체를 순회할 수 있으며,
      객체 A는 MoveNext 메소드에 접근하고, 메소드가 true이면 Current 메소드에 접근하여 컬렉션의 요소를 읽을 수 있다. .
	    List<string> list = new List<string>() {
    
     "25", "哈3", "26", "花朵" };
 		IEnumerator listEnumerator = list.GetEnumerator();
        while (listEnumerator.MoveNext())
        {
    
    
            Console.WriteLine(listEnumerator.Current);
        }
24. Foreach 루프가 반복될 때 요소가 삭제되면 프로그램에서 오류를 보고합니다. 해당 요소를 찾는 방법은 무엇입니까? 그리고 이 상황을 구체적으로 어떻게 처리해야 할까요? (참고: Try...Catch는 예외를 포착하고 정보 전송은 불가능합니다.)
  • foreach는 반복자가 반복 컬렉션을 잠그기 때문에 요소를 삭제할 수 없습니다. 해결 방법: 발견된 인덱스 또는 키 값을 기록한 다음 반복이 완료된 후 삭제합니다.
25.JIT와 AOT의 차이점
  • Just-In-Time - 실시간 컴파일,
    느린 설치 및 빠른 설치, 더 적은 공간 차지
  • Ahead-Of-Time - 사전 컴파일되어
    실행이 빠르고 설치가 느리며 많은 양의 메모리와 외부 메모리를 차지합니다.
26. 매개변수를 저장할 배열이 주어지면 배열을 재배열하세요.
  • 무효 SortArray(배열 arr){Array.Sort(arr);}
27. 객체를 자주 생성하고 사용해야 할 때 메모리를 절약할 수 있는 좋은 프로그래밍 솔루션은 무엇입니까?
  • 객체를 생성하거나 객체 풀을 사용하기 위한 싱글톤 패턴 설계
28.C#의 델리게이트란 무엇이며, 용도는 무엇인가요?
  • 델리게이트는 안전한 포인터 참조와 유사하며, 사용 시 메서드가 아닌 클래스로 취급되며 메서드 목록에 대한 참조와 동일합니다. 델리게이트를 사용하여 이 메서드 세트에 대해 편리하게 작업할 수 있습니다. 대리자는 함수 포인터를 캡슐화한 것입니다.
  • 유용성: 대리자를 사용하면 프로그래머가 대리자 개체 내에 메서드 참조를 캡슐화할 수 있습니다. 그런 다음 컴파일 타임에 어떤 메서드가 호출될지 알 필요 없이 참조된 메서드를 호출할 수 있는 코드에 해당 대리자 개체를 전달할 수 있습니다. C 또는 C++의 함수 포인터와 달리 대리자는 개체 지향적이고 형식이 안전합니다.
29.C#에서 대리자와 이벤트의 차이점
  • 대략적으로 말하면 대리자는 메서드를 가리키는 필드를 내부적으로 유지 관리하는 클래스입니다. 이벤트는 대리자 유형 변수로 볼 수 있으며, 이벤트를 통해 여러 대리자 또는 메서드를 등록하고 취소할 수 있습니다.
  • 대리자는 "="를 사용하여 값을 할당할 수 있지만 이벤트는 그렇지 않습니다.
  • 대리자는 선언된 클래스 외부에서 호출할 수 있지만 이벤트는 클래스 내부에서만 호출할 수 있습니다.
  • 대리자는 유형이고 이벤트는 객체를 수정합니다.
  • 대리자는 인스턴스화할 수도 있는 클래스입니다. 대리자의 생성자를 통해 대리자 인스턴스에 메서드가 할당됩니다.
  • Delegate를 발생시키는 방법에는 두 가지가 있는데 Delegate 인스턴스.Invoke(파라미터 목록), Delegate 인스턴스(파라미터 목록)
    이벤트는 Delegate 형태의 변수로 간주할 수 있으며 +=, -=를
    통해 해당 이벤트에 대한 여러 개의 Delegate 인스턴스 또는 여러 메서드를 등록합니다.
    이벤트 취소 다중 대리자 인스턴스 또는 다중 메소드
    EventHandler는 대리자입니다.
30.C#에서 위임과 인터페이스의 차이점은 무엇인가요? 각각은 어떤 상황에서 사용되나요?
  • 인터페이스는 클래스가 가져야 할 기능을 제한하는 기능의 집합으로, 클래스가 가져야 할 기능을 제한하고, 시시각각 변화하는 특정 로직에서 클래스를 해방시키며, 클래스의 관리 및 확장을 용이하게 하며 동시에 합리적으로 해결해 줍니다. 클래스의 단일 상속 문제.
    C#의 대리자는 메서드 컬렉션을 제한하는 클래스입니다. 대리자를 사용하여 이 메서드 컬렉션에 대해 작업을 편리하게 수행할 수 있습니다.
  • 다음 상황에서는 인터페이스를 사용하십시오.
    • 상속을 사용할 수 없는 경우
    • 완전히 추상적인 상황
    • 여러 사람이 협력하는 상황
31.인터페이스와 추상 클래스
  • 개념
    • 추상 클래스
      두 개 이상의 클래스에 중복된 부분이 있는 경우 기본 클래스를 추상화할 수 있으며, 이 기본 클래스가 인스턴스화되지 않기를 바라는 경우 이 기본 클래스를 추상 클래스로 설계할 수 있습니다.
      일부 클래스에 공통 구현 코드를 제공해야 하는 경우 추상 클래스에 우선순위를 부여해야 합니다. 추상 클래스의 비추상 메서드는 하위 클래스에서 상속될 수 있으므로 함수를 구현하는 코드가 더 간단합니다.
    • 인터페이스
      코드 확장성과 유지 관리성에 중점을 둘 때 인터페이스를 먼저 사용해야 합니다.
      인터페이스와 이를 구현하는 클래스 사이에 계층적 관계가 있을 필요는 없습니다. 인터페이스는 관련 없는 클래스와 동일한 동작을 달성할 수 있으므로 추상 클래스를 사용하는 것보다 더 편리하고 유연합니다. 인터페이스는 상호 작용에만 관심을
      갖습니다. 객체가 아닌 객체 간의 메소드 해당 특정 클래스. 인터페이스는 프로그램 간의 프로토콜로, 추상 클래스를 사용하는 것보다 더 안전하고 명확합니다. 일반적으로 인터페이스가 더 자주 사용됩니다.
  • 차이점
    • 인터페이스는 클래스가 아니므로(생성자와 소멸자가 없음) 인스턴스화할 수 없습니다. 추상 클래스는 간접적으로 인스턴스화할 수 있습니다(상속될 수 있고 생성자를 가지며 추상 클래스의 상위 클래스를 간접적으로 인스턴스화하는 동시에 하위 클래스를 인스턴스화할 수 있음).
    • 인터페이스는 메서드 선언만 할 수 있는 반면 추상 클래스는 메서드 선언과 메서드 구현을 만들 수 있습니다.
    • 추상 클래스에는 구현 멤버가 있을 수 있고 인터페이스에는 추상 멤버만 포함될 수 있습니다. 따라서 인터페이스는 완전히 추상적이고 추상 클래스는 부분적으로 추상입니다.
    • 추상 클래스는 하위 클래스에서 상속되어야 하며 인터페이스는 클래스에서 구현되어야 합니다.
    • 추상 클래스의 모든 멤버 수정자를 사용할 수 있으며 인터페이스의 멤버는 외부이므로 수정자가 필요하지 않습니다.
    • 인터페이스는 다중 상속을 구현할 수 있고, 추상 클래스는 단일 상속만 구현할 수 있으며, 클래스는 하나의 클래스만 상속할 수 있지만 여러 인터페이스를 구현할 수 있습니다.
    • 추상 메서드는 구현해야 하므로 정적이거나 비공개일 수 없습니다.
  • 사용 사례 추상 클래스를 사용하는 이유는
    코드 재사용을 위한 것이고, 인터페이스를 사용하는 동기는 다형성을 달성하기 위한 것입니다.
    특정 필드에 내재된 속성, 즉 본질을 정의하는 데에는 추상 클래스가 적합하고, 특정 필드의 확장 기능을 정의하는 데에는 인터페이스가 적합합니다.
32. 함수 내에서 문자열 +=를 여러 번 사용하면 메모리 쓰레기(가비지 조각)가 많이 생성되는데, 이를 해결할 수 있는 좋은 방법이 없을까요?
  • 메모리 쓰레기를 줄일 수 있는 StringBuilder를 통해 추가합니다.
33.C#과 C++의 차이점은 무엇인가요?
  • 간단히 말하면 C#과 C++를 비교할 때 가장 중요한 특징은 C#은 완전한 객체지향 언어인 반면 C++는 그렇지 않다는 점입니다. 또한 C#은 IL 중간 언어
    와 .NET Framework CLR을 기반으로 한다는 점에서 그렇습니다. 이식성 및 유지 관리성, 성능과 견고성 모두 C++에 비해 크게 향상되었습니다. C#의 디자인 목표는 빠르고 안정적이며 확장 가능한 애플리케이션을 개발하는 것입니다. 물론 일부 하위 수준 작업은 Interop 및 Pinvoke를 통해 완료할 수도 있습니다.
  • 구체적인 비교:
    • 상속: C++는 다중 상속을 지원합니다. C# 클래스는 하나의 기본 클래스의 구현만 상속할 수 있지만 여러 인터페이스를 구현할 수 있습니다.
    • 배열: C# 배열 선언 구문은 C++ 배열 선언과 다릅니다. C#에서는 배열 유형 뒤에 "[]" 표시가 나타납니다.
    • 데이터 유형: C++에서는 bool 클래스를 정수 유형으로 변환할 수 있지만 C#에서는 bool 유형과 다른 유형(특히 int) 간의 변환이 없습니다. long 유형: long 데이터 유형은 C#에서는 64비트이고 C++에서는 32비트입니다.
    • 구조체 유형: C#에서 클래스와 구조체는 의미상 다릅니다. struct는 값 유형이고 클래스는 참조 유형입니다.
    • Switch 문: C++의 switch 문과 달리 C#에서는 한 사례 레이블에서 다른 사례 레이블로 전달을 지원하지 않습니다.
    • 위임 유형: 위임은 기본적으로 C++의 함수 포인터와 유사하지만 전자는 유형 안전성이 있고 안전합니다.
      파생 클래스에서 호출될 때 기본 클래스 멤버를 재정의합니다. base는 new 수정자를 사용하여 상속된 멤버를 명시적으로 숨깁니다.
      메서드를 재정의하려면 부모 클래스 메서드의 virtual 선언과 하위 클래스 메서드의 override 키워드를 사용해야 합니다.
      전처리기 지시문은 조건부 컴파일에 사용됩니다. C#에서는 헤더 파일이 사용되지 않습니다. C# 전처리기 지시문
    • 예외 처리: finally 문은 C#에서 도입되었으며 C++에서는 사용할 수 없습니다.
    • C# 연산자: C#은 is 및 typeof와 같은 다른 연산자를 지원합니다. 또한 특정 논리 연산자의 다양한 기능을 소개합니다.
    • 정적을 사용하면 정적 메서드는 클래스 이름으로만 호출할 수 있고 정적 변수를 변경할 수 있습니다.
  • 생성된 기본 클래스의 C++ 초기화 목록에 대한 대안입니다.
    • Main 메소드는 C++, Java의 main 함수와 다르게 선언되므로 Main 대신 Main을 사용할 수 없습니다.
    • 메서드 매개 변수: C#에서는 포인터를 대체하고 매개 변수를 참조로 전달하는 ref 및 out 매개 변수를 지원합니다.
    • C#에서 포인터는 안전하지 않은 모드에서만 사용할 수 있습니다.
    • 오버로드된 연산자는 C#에서 다르게 수행됩니다.
    • 문자열: C# 문자열은 C++ 문자열과 다릅니다.
    • foreach: C#에서는 VB의 foreach 키워드를 도입하여 배열과 컬렉션을 반복합니다.
    • C#에는 전역 메서드와 전역 변수가 없습니다. 메서드와 변수는 형식 선언(예: 클래스 또는 구조체)에 포함되어야 합니다.
    • C#에는 헤더 파일과 #include 지시문이 없습니다. using 지시문은 정규화된 형식 이름이 없는 다른 네임스페이스의 형식을 참조하는 데 사용됩니다.
    • C#의 지역 변수는 초기화될 때까지 사용할 수 없습니다.
  • 소멸자: C#에서는 소멸자가 가비지 수집기에 의해 자동으로 호출되므로 소멸자가 호출되는 시기를 제어할 수 없습니다. 오물 소각로
  • 생성자: C++와 마찬가지로 C#에서 클래스 생성자가 제공되지 않으면 기본 생성자가 자동으로 생성됩니다. 이 기본 생성자는 모든 필드를 기본값으로 초기화합니다.
    C#에서는 메서드 매개 변수에 기본값이 있을 수 없습니다. 동일한 효과를 얻으려면 메서드 오버로딩을 사용해야 합니다.
34. 리플렉션은 어떻게 구현되나요?
  • 로더가 실행 중일 때 어셈블리를 동적으로 얻어 로드할 수 있으며, 어셈블리의 정보 반영을 얻을 수 있는데 이는 런타임 중에 클래스, 개체, 메서드, 개체 데이터 등을 동적으로 가져오는 중요한 수단입니다.
    주로 사용되는 클래스 라이브러리: System.Reflection
  • 핵심 수업:
    • 어셈블리는 어셈블리를 설명합니다.
    • 유형은 클래스 유형을 설명합니다.
    • ConstructorInfo는 생성자를 설명합니다.
    • MethodInfo는 모든 메소드를 설명합니다.
    • FieldInfo는 클래스의 필드를 설명합니다.
    • PropertyInfo는 클래스의 속성을 설명합니다.
  • 위의 핵심 클래스를 통해 런타임 시 어셈블리에서 클래스를 동적으로 획득하고, 클래스 생성을 실행하여 클래스 객체를 생성하고, 객체 필드 또는 속성 값을 동적으로 획득하고, 클래스 메서드 및 인스턴스 메서드를 동적으로 실행할 수 있습니다.
    메타데이터를 검사하고 그에 대한 유형 정보를 수집하는 기능입니다.
    구현 단계:
1. 导⼊using System.Reflection;
2. Assembly.Load("程序集")加载程序集,返回类型是
⼀个Assembly
3.  foreach (Type type in assembly.GetTypes())
         {
    
    
            string t = type.Name;
         }
得到程序集中所有类的名称
4. Type type = assembly.GetType("程序集.类名");获取
当前类的类型
5. Activator.CreateInstance(type); 创建此类型实例
6. MethodInfo mInfo = type.GetMethod("⽅法名");获取
当前⽅法
7. mInfo.Invoke(null,⽅法参数);
35.C#에서 기본 유형이 차지하는 바이트 수
유형 바이트
부울 허위 사실
바이트、문자 1바이트
문자, 짧은 2바이트
정수, 부동 t4바이트
긴、더블 8바이트
36.Mock과 Stub의 차이점은 무엇인가요?
  • Mock과 Stub의 차이점: Mock: 동작 검증에 중점을 둡니다. 세분화된 테스트, 즉 코드의 논리는 대부분의 경우 단위 테스트에 사용됩니다. 스텁: 상태 확인에 주의하세요. 대략적인 테스트는 파일 시스템 액세스, 데이터베이스 연결, 원격 프로토콜 등과 같이 종속 시스템이 존재하지 않거나 구현되지 않았거나 테스트하기 어려운 경우에 사용됩니다.
37. StringBuilder와 String의 차이점을 간략하게 설명해주세요. (문자열 처리)
  • 문자열은 문자열 상수입니다. StringBuilder는 문자열 변수이며 스레드에 안전하지 않습니다.
  • String 유형은 불변 객체입니다. String을 변경할 때마다 새 String 객체를 생성한 다음 포인터가 새 객체를 가리켜야 합니다. 루프에 있는 경우 계속 변경됩니다. 객체의 경우 계속해서 새로운 객체를 생성해야 하므로 효율성이 매우 낮으며, String 객체가 지속적으로 변경되는 String 타입은 사용하지 않는 것이 좋습니다.
  • StringBuilder 개체는 문자열 연결 작업을 수행할 때 원래 문자열을 수정하여 성능을 향상시킵니다. 일상적으로 사용해보면 다들 아시겠지만, 연결 작업이 자주 발생하는 경우에는 StringBuilder 개체가 사용됩니다.
38. 사전 사전의 내부 구현 원리
  • System.Collections.Generic을 사용하는 일반 컬렉션 네임스페이스;
    모든 키는 고유해야 합니다.
    이 클래스의 가장 큰 장점은 요소를 찾는 시간 복잡도가 O(1)에 가깝다는 것입니다. 실제 프로젝트에서는 일부 데이터를 캐시하는 데 자주 사용됩니다. 로컬로 전반적인 효율성을 향상시킵니다.
  • 구현원리
    • 해시 알고리즘: HashFunc를 통해 HashCode를 얻기 위해 키를 사용하여 가변 길이 바이너리 데이터 세트를 더 짧은 바이너리 길이 데이터 세트에 매핑합니다.
    • 해시 버킷 알고리즘: HashCode를 세그먼트로 표시합니다. 일반적인 방법은 HashCode의 나머지 부분을 직접 가져와
      충돌 충돌을 해결하는 것입니다. 알고리즘(지퍼 방식): 분할하면 키에 해당하는 버킷이 동일해집니다. ​​지퍼 방식은 충돌하는 요소와 같아서 단일 연결 리스트를 생성하고 해당 해시 버킷 위치에 헤드 포인터를 저장합니다. 반대로, 해시 버킷의 위치를 ​​결정한 후 단일 연결 리스트를 순회하여 해당 값을 얻습니다.
39.사용의 역할
  • 리소스: IDisposable 인터페이스를 구현하는 클래스 또는 구조입니다.
    using 문은 이러한 리소스가 적절하게 해제될 수 있도록 보장합니다(Resource.Dispose).
  • 사용 원칙: 사용(리소스 할당) {리소스 사용} ——> 리소스 해제(암시적으로),
    리소스 사용(예외 발생 가능)은 Try 블록에 배치되고 리소스 해제(예외 포함 또는 제외)는 Try 블록에 배치됩니다. 마침내 차단하다
using(分配资源)
{
    
    
	try{
    
     使用资源 }
	finally{
    
     Resource.Dispose}
}
  • Using 지시문은 소스 파일 상단에 using+namespace(혹은 네임스페이스 타입)을 선언하고 있으며,
    멤버 메소드 호출 시 using을 사용하지 않고 직접 네임스페이스.class.member 메소드를 사용할 수도 있다.
40.Mathf.Round, Mathf.Clamp 및 Mathf.Lerp는 무엇을 의미하나요?
  • Mathf.Round: 반올림
  • Mathf.Clamp: 왼쪽 및 오른쪽 제한
  • Mathf.Lerp: 보간
41. foreach 순회를 사용하여 액세스할 수 있는 개체는 ___ 인터페이스를 구현하거나 ___ 메서드 유형을 선언해야 합니다(C# 순회).
  • IEnumerable;GetEnumerator
  • 목록 및 사전 유형은 foreach를 사용하여 탐색할 수 있으며 둘 다 IEnumerable 인터페이스를 구현하고 GetEnumerator 메서드를 선언합니다.
42.리스코프 대체원리는 무엇인가요? (C# 다형성)
  • Liskov 대체 원리 LSP는 객체 지향 설계의 기본 원리 중 하나입니다.
    • Liskov 대체 원칙은 기본 클래스가 나타날 수 있는 모든 곳에 기능적 기능 확장을 촉진하기 위해 하위 클래스가 나타나야 한다고 말합니다.
    • 하위 클래스는 상위 클래스의 추상 메서드를 구현할 수 있지만 상위 클래스의 비추상 메서드를 재정의할 수는 없습니다.
    • 서브클래스는 고유한 메서드를 추가할 수 있습니다.
    • 하위 클래스가 상위 클래스 메서드를 재정의하거나 구현할 때 메서드의 전제 조건(즉, 메서드의 형식 매개변수)은 상위 클래스 메서드의 입력 매개변수보다 더 완화됩니다.
    • 하위 클래스의 메서드가 상위 클래스의 추상 메서드를 구현할 때 메서드의 사후 조건(즉, 메서드의 반환 값)은 상위 클래스의 사후 조건보다 더 엄격합니다.
43. for 루프에서 목록(또는 벡터 등)의 요소를 삭제하려고 할 때 발생할 수 있는 문제와 이를 방지하는 방법은 무엇입니까?
  • 순회된 노드 뒤의 노드가 삭제되면 List.Count가 변경되며, 해당 요소가 삭제된 후 i++에 따라 삭제된 노드로 순회할 때 예외가 발생합니다.
  • 처리 방법: 요소를 뒤에서 앞으로 순회할 수 있습니다. 즉, 액세스 앞에서 요소를 삭제할 수 있습니다.
44. C#의 프록시 및 이벤트 개요?
  • 프록시는 메서드에 대한 참조를 정의하는 데 사용됩니다.
    C# 이벤트의 본질은 개체 간 통신에 사용되는 메시지 캡슐화이며, 보낸 사람을 이벤트 보낸 사람, 받는 사람을 이벤트 수신기라고 합니다.
45.새로운 구현 로직
  • rPoint1 = new RefPoint(1);
  • 애플리케이션 힙에 참조 형식 개체의 인스턴스를 만들고 여기에 메모리 주소를 할당합니다.
    인스턴스에 대한 참조를 생성자에 자동으로 전달합니다(이러한 이유로 이를 사용하여 생성자의 인스턴스에 액세스할 수 있습니다).
    유형의 생성자를 호출합니다.
  • 인스턴스의 참조 메모리 주소를 반환하고 이를 rPoint1 변수에 복사합니다. rPoint1 참조 개체에 의해 저장된 데이터는 힙에 생성된 이 유형의 인스턴스 주소를 가리킵니다.
46. ​​​​클래스 선언과 함수 선언에서 Sealed 키워드의 역할을 간략하게 설명해주세요.
  • 클래스 선언은 다른 클래스가 이 클래스를 상속하는 것을 방지하고, 메서드에 선언하면 파생 클래스가 이 메서드를 재정의하는 것을 방지합니다.
47. 다음 코드를 실행하면 어떤 문제가 발생합니까? 그것을 피하는 방법?
List<int> ls = new List<int>(new int[]{
    
     1, 2, 3, 4, 5 });
         foreach (int item in ls)
         {
    
    
             Console.WriteLine(item * item);
             ls.Remove(item);
         }
  • foreach는 읽기 전용이므로 런타임 오류가 발생합니다. 이동 중에는 수정할 수 없습니다.
    이는 For 루프를 사용하여 해결할 수 있습니다.
48. 포장 및 개봉이란 무엇이며 작업을 줄이는 방법은 무엇입니까?
  • C# boxing은 값 유형을 참조 유형으로 변환합니다.
  • Unboxing은 참조 유형을 값 유형으로 변환하는 것입니다.
    컬렉션은 대부분 ArrayList 또는 HashTable과 같은 boxing 및 unboxing 작업과 관련됩니다.
  • 값 유형과 참조 유형을 서로 변환: unboxing 및 boxing
    • Boxing: 값 유형 ====》참조 유형 객체는
      메모리 힙을 할당합니다.
      값 유형 데이터는 새 메모리 힙에 복사됩니다.
      스택에 새 참조 주소가 할당되어 메모리 힙을 가리킵니다.
    • 언박싱: 참조 유형 객체====》값 유형
      객체가 주어진 값 유형의 박스형 값인지 확인하십시오.
      값 데이터를 스택의 값 유형에 복사합니다.
49.MVC
  • MVC의 정식 명칭은 Model View Controller로, Model-View-Controller의 약자로 소프트웨어 설계 모델입니다.
    비즈니스 로직, 데이터, 인터페이스 표시를 분리하는 방법을 사용하여 비즈니스 로직을 하나의 구성 요소로 집약하며, 인터페이스와 사용자 상호 작용을 개선하고 개인화하면서 비즈니스 로직을 다시 작성할 필요가 없습니다. MVC는 전통적인 입력, 처리 및 출력 기능을 논리적 그래픽 사용자 인터페이스 구조로 매핑하기 위해 고유하게 개발되었습니다.
    • 모델은 애플리케이션 데이터의 논리를 처리하는 애플리케이션의 일부입니다.
        일반적으로 모델 개체는 데이터베이스의 데이터에 액세스하는 역할을 담당합니다.
    • 보기는 데이터 표시를 처리하는 응용 프로그램의 일부입니다.
        일반적으로 뷰는 모델 데이터에서 생성됩니다.
    • 컨트롤러는 사용자 상호 작용을 처리하는 애플리케이션의 일부입니다.
        일반적으로 컨트롤러는 뷰에서 데이터를 읽고, 사용자 입력을 제어하고, 모델에 데이터를 보내는 일을 담당합니다.
50. 관리되지 않는 코드와 안전하지 않은 코드
  • 관리 코드: CLR(공용 언어 런타임)의 제어 하에 실행되는 코드입니다.
  • 비관리 코드: CLR(공용 언어 런타임)의 제어 하에 실행되지 않는 코드입니다.
  • 안전하지 않은 코드: 안전하지 않은 코드는 관리 코드와 비관리 코드 사이의 어딘가에 있다고 생각할 수 있습니다. 안전하지 않은 코드는 CLR(공용 언어 런타임) 제어 하에서 계속 실행되지만 포인터를 통해 메모리에 직접 액세스할 수 있습니다.
51.힙과 스택의 차이점은 무엇인가요?
  • 힙은 힙이고 스택은 스택입니다.
  • 스택 공간은 운영 체제에 의해 자동으로 할당 및 해제되고, 힙 공간은 수동으로 적용 및 해제되며, 힙은 new 키워드로 할당되는 경우가 많습니다.
  • 스택 공간은 제한되어 있고 힙 공간은 여유 공간이 넓습니다.
52. 스택 오버플로의 일반적인 원인은 무엇입니까?
  • 무한 재귀. 함수가 재귀적으로 호출되면 시스템은 함수 호출 장면과 스택에 생성된 변수를 지속적으로 저장해야 하는데, 재귀 호출이 너무 깊어지면 스택 오버플로가 발생하여 재귀가 반환되지 않습니다. 또한 함수 호출 수준이 너무 깊으면 스택이 이러한 호출의 반환 주소를 수용하지 못해 스택 오버플로가 발생할 수 있습니다.
    무한 루프.
  • 지역 변수 할당이 많습니다.
53. 스택과 큐
  • 같은 점:
    • 그것들은 모두 선형 구조입니다.
    • 삽입 작업은 테이블 끝으로 제한됩니다.
    • 모두 순차구조와 체인구조를 통해 실현 가능합니다.
    • 삽입과 삭제의 시간복잡도는 O(1)이고, 공간복잡도도 같다.
    • 멀티체인 스택과 멀티체인 큐의 관리 모드는 동일할 수 있습니다.
    • 맨 아래 레이어는 일반 배열로 구현됩니다.
  • 차이점:
    • 스택은 선입선출, 큐는 선입선출: 데이터 요소를 삭제하는 위치가 다릅니다.스택의 삭제 작업은 테이블 끝에서 수행되고 큐의 삭제 작업은 테이블의 머리 부분에서 수행됩니다.
    • 순차 스택은 다중 스택 공간 공유를 실현할 수 있지만 순차 큐는 그렇지 않습니다.
  • 다양한 애플리케이션 시나리오
    • 일반적인 스택 애플리케이션 시나리오는 다음과 같습니다.
    • 브라켓 문제를 해결하고,
    • 깊이우선탐색 순회 등
    • 함수 호출 및 재귀 구현,
      표현식 변환 및 평가
  • 일반적인 대기열 애플리케이션 시나리오는 다음과 같습니다.
    • 컴퓨터 시스템의 다양한 자원 관리,
    • 메시지 버퍼 관리
    • 너비 우선 검색 순회 등
54. 연결리스트 관련
  • 단일 연결 목록과 이중 연결 목록의 차이점은 다음과 같습니다.
    • 포인팅은 다릅니다. 단방향 연결 목록에는 다음 노드에 대한 포인터가 하나만 있는 반면, 이중 연결 목록에는 다음 노드에 대한 포인터 외에 이전 노드에 대한 포인터도 있습니다.
    • 기능은 다릅니다. 단방향 연결 목록은 다음에만 올 수 있지만 이중 연결 목록은 반환될 수 있습니다.
    • 단일 연결 목록과 양방향 연결 목록은 다릅니다. 단일 연결 목록은 한 방향으로만 읽을 수 있지만 이중 연결 목록은 양방향으로 탐색할 수 있습니다.
  • 단방향 연결리스트의 장점과 단점:
    • 장점: 단방향 연결리스트에서는 노드를 추가하고 삭제하기가 쉽습니다. 횡단할 때 무한 루프가 발생하지 않습니다.
    • 단점: 처음부터 끝까지만 탐색할 수 있습니다. 우리는 전임자가 아닌 후임자만 찾을 수 있습니다. 즉, 앞으로 나아갈 수만 있습니다.
  • 이중 연결 리스트의 장점과 단점:
    • 장점: 전임자와 후임자를 찾을 수 있고, 전진하고 후퇴할 수 있습니다.
    • 단점: 노드 삭제의 복잡성을 추가하려면 포인터 저장 공간을 할당해야 합니다.
55. 연결리스트와 배열의 비교
  • 배열은 미리 정의된 고정 길이(요소 수)를 가져야 하며 데이터의 동적 증가 또는 감소에 적응할 수 없습니다. 데이터가 증가하면 원래 정의된 요소 수를 초과할 수 있고, 데이터가 감소하면 메모리 낭비가 발생하며, 첨자에 따라 배열에 직접 접근할 수 있으며 시간 복잡도는 O(1)입니다.
  • 연결된 목록은 저장소를 동적으로 할당하고, 데이터의 동적 증가 및 감소에 적응할 수 있으며, 데이터 항목을 쉽게 삽입하고 삭제할 수 있습니다. (배열에 데이터 항목을 삽입하거나 삭제할 때 다른 데이터 항목을 이동해야 하는데 이는 매우 번거롭습니다.) 연결 리스트는 다음 포인터를 기준으로 다음 요소를 찾아야 합니다.
  • 데이터에 빠르고 드물게 접근해야 하거나 요소 삽입 및 삭제 없이 데이터에 접근해야 한다면 배열을 사용하고, 반대로 요소를 자주 삽입하고 삭제해야 한다면 연결리스트 데이터 구조를 사용해야 합니다.
56.이진트리 관련
  • 깊이(높이) 계산
    이진 트리의 높이는 이진 트리의 노드 수준의 최대값, 즉 왼쪽 및 오른쪽 하위 트리의 최대 높이 + 1입니다. 트리가 비어 있으면 높이는 0이고, 그렇지 않으면 왼쪽 및 오른쪽 하위 트리의 최대 높이는 +1입니다.
  • 순회: (루트 노드의 위치를 ​​확인)
    • 선주문 순회: (루트의 왼쪽 및 오른쪽) 루트 노드를 먼저 방문한 다음 왼쪽 노드, 오른쪽 노드를 방문합니다.
    • 순차 순회: (왼쪽 루트 오른쪽) 먼저 왼쪽 노드를 방문한 다음 루트 노드, 오른쪽 노드를 방문합니다.
    • 후위 순회: (왼쪽 및 오른쪽 루트) 먼저 왼쪽 노드를 방문한 다음 오른쪽 노드, 루트 노드를 방문합니다.
57. 사전 관련
  • 소개:
    사전은 키와 값의 모음을 나타냅니다.
    Dictionary<object, object>는 일반 유형입니다.
    그 자체로 컬렉션의 기능을 가지고 있으며 때로는 배열로 간주될 수도 있습니다.
    그 구조는 다음과 같습니다: Dictionary<[key], [value]>.
    그 특징은 저장된 객체가 [key] 값과 일대일 대응으로 일반 유형으로 저장되어야 하며 모든 키가 고유하다는 것입니다.
    특정 [키]를 통해 해당 값을 찾습니다. 요소를 찾는 시간 복잡도는 O(1)입니다.
    Dictionary 사전 클래스를 추가, 삭제, 확인, 수정하는 시간 복잡도
    는 해시 테이블이고 Add 연산은 O(1)이다.
    Containskey 메서드는 요소를 순회하는 대신 해싱을 사용하여 요소를 찾기 때문에 O(1)입니다.
    값을 해시하는 대신 키를 탐색하여 내부적으로 찾기 때문에 ContainsValue 메서드의 시간 복잡도는 O(N)입니다.
    ltem[Key] 속성은 키를 기준으로 값을 검색하며 시간 복잡도도 O(1)입니다.
    기본적으로 O(1)
  • 기본 구현 원칙:
    Dictionary는 생성 시 다음 작업을 수행합니다.
    1. 버킷 배열 초기화 this.buckets = new int[prime]
    2. this.entries = new Entry<TKey, TValue>[prime]
    버킷 초기화 항목 및 항목의 용량은 사전의 용량보다 큰 최소 소수입니다
    . This.buckets는 주로 해시 충돌에 사용됩니다
    . This.entries는 사전의 내용을 저장하고 다음 요소의 위치를 ​​식별하는 데 사용됩니다.
  • 자세한 과정:
    • 해시 테이블 방법: 가변 길이 바이너리 데이터 세트를 더 짧은 바이너리 데이터 세트에 매핑하고 Key는 HashFunc를 통해 HashCode를 가져옵니다.
    • 해시 버킷 알고리즘: HashCode를 세그먼트로 표시합니다. 일반적으로 사용되는 방법은 HashCode의 나머지 부분을 직접 가져오는 것입니다.
    • 지퍼 방식: 분할하면 키에 해당하는 해시 버킷이 동일해집니다. 지퍼 방식의 기본 아이디어는 충돌하는 요소에 대해 단일 연결 리스트를 생성하고 해당 위치에 헤드 포인터를 저장하는 것입니다. 해시 버킷. 반대로 해시 버킷에 대응한 후 단일 연결 리스트를 순회하여 값을 얻습니다.
58. 해시 테이블과 사전 비교
  • 사전: Hashtable은 내부적으로 저장 구조로 사용되며,
    존재하지 않는 키를 찾으려고 하면 예외를 반환/발생시킵니다.
    특히 값 유형의 경우 박싱 및 언박싱이 없기 때문에 해시 테이블보다 빠릅니다.
    공용 정적 멤버만 스레드로부터 안전합니다.
    사전은 일반 유형이므로 모든 데이터 유형과 함께 사용할 수 있습니다(생성 시 키와 값 모두의 데이터 유형을 지정해야 함).
    Dictionay는 Hashtable의 유형 안전 구현이며 키와 값은 강력한 유형입니다.
    Dictionary가 출력을 탐색하는 순서는 출력이 추가되는 순서입니다.
  • 해시 테이블:
    존재하지 않는 키를 찾으려고 하면 null이 반환됩니다.
    boxing과 unboxing이 필요하기 때문에 사전보다 속도가 느립니다.
    해시 테이블의 모든 멤버는 스레드로부터 안전하고,
    해시 테이블은 범용 유형이 아니며,
    해시 테이블은 느슨한 유형의 데이터 구조이므로 모든 유형의 키와 값을 추가할 수 있습니다.
    HashTable은 최적화되어 있으며, 첨자로 접근하는 객체가 먼저 해싱되므로 내부 해싱은 순서가 없습니다.
59. List와 Dictionary의 순회 및 쿼리 효율성에 대하여
  • List의 맨 아래 레이어는 연속적이고 긴밀한 순서로 저장되는 일반적인 배열이며 일반적으로 데이터는 캐시에 저장됩니다. 사전은 배열과 해시 테이블로 구성된 이산(해시) 분포이며, 순회할 때 페이지 변경 작업이 발생하고 배열이 메모리에 저장됩니다. 읽기 및 쓰기 속도는 캐시>메모리>하드디스크입니다. 따라서 List는 순회에 더 적합합니다.
  • 사전의 질의 효율성은 요소의 키 값에 대해 나머지 연산을 수행하여 해당 해시 버킷을 찾아 해당 해시 버킷에 해당하는 해시 테이블의 헤드 노드가 요소인지 여부를 확인하는 것입니다. 수행되지 않으면 해시 테이블은 순회 수행이며 두 프로세스 모두 상수 수준 작업입니다. 따라서 O(1)입니다. List의 쿼리 효율성은 해당 값을 찾기 위해 먼저 순회하는 것이므로 O(n)입니다. 따라서 쿼리에는 사전이 더 적합합니다.
60.Stack의 최하위 레이어는 어떻게 구현되나요?
  • Stack도 내부적으로 배열로 구현되는데, List와 마찬가지로 용량의 2배로 확장되지만 기본 용량이 다르며, Stack은 기본적으로 10개의 용량으로 배열을 구성합니다.
61.딕셔너리와 해시테이블의 차이점은 무엇인가요?
  • Hashtable은 다중 스레드 읽기/쓰기에 대해 스레드로부터 안전하지만 Dictionary는 그렇지 않습니다. 여러 스레드 간에 사전 읽기/쓰기 작업을 공유하려면 스레드 안전을 보장하기 위해 잠금을 직접 작성해야 합니다.
  • 딕셔너리의 키와 값은 일반 저장소이고 데이터 유형이 고정되어 있으며 유형 변환이 필요하지 않습니다. 해시테이블의 키와 값은 모두 객체입니다. 값을 저장하거나 읽을 때 박싱과 언박싱이 발생하므로 시간이 많이 걸리고 다음 작업에 적합합니다. 데이터 유형이 고유하지 않습니다.
  • Dictionary는 저장된 값의 삽입 순서를 유지하지만 HashTable은 키 값 데이터가 삽입되는 순서를 유지하지 않습니다.
    net/sinat_34014668/article/details/127039207
62. 교합 제거의 원리는 무엇입니까?
  • 오클루전 컬링은 가상 카메라를 사용하여 장면을 탐색하여 잠재적으로 표시되는 객체의 계층 구조를 구축합니다. 런타임 시 각 카메라는 이 데이터를 사용하여 표시되는 객체와 다른 객체에 의해 가려지는 객체를 식별합니다. 오클루전 컬링 기술을 사용하면 처리되는 정점 수를 줄일 수 있을 뿐만 아니라 오버드로를 줄이고 게임 성능을 향상시킬 수 있습니다.
63. 인터페이스와 추상 클래스의 차이점은 무엇입니까?
  • 인터페이스는 작업의 추상화이고 추상 클래스는 동일한 유형의 추상화입니다. 추상 클래스는 이 객체가 무엇인지 나타냅니다. 인터페이스는 이 개체가 수행할 수 있는 작업을 나타냅니다.
  • 인터페이스를 상속하는 클래스는 모든 메서드를 구현해야 하며 인터페이스를 사용하여 일부 동작을 정의할 수 있습니다. 둘 다 인스턴스화할 수 없습니다. 예를 들어 "문"을 추상 클래스로 정의하면 특정 상황에 따라 철문, 나무 문 등으로 인스턴스화될 수 있습니다. 문은 열리는 동작을 가지며 이러한 열리는 동작은 다음과 같이 정의될 수 있습니다. 인터페이스. C# 클래스는 여러 소스에서 상속될 수 없지만 인터페이스는 여러 소스에서 상속될 수 있습니다. . 추상 기본 클래스는 필드, 속성 및 메서드 구현을 정의할 수 있습니다. 인터페이스는 속성, 인덱서, 이벤트 및 메서드 선언만 정의할 수 있으며 필드를 포함할 수 없습니다. 추상 클래스에는 추상 메서드와 비추상 메서드가 모두 포함될 수 있습니다.
64.Const와 ReadOnly의 차이점은 무엇인가요?
  • 초기화 위치가 다릅니다. const는 선언 시 할당되어야 하며, readonly는 선언이나 정적 생성자에서 할당될 수 있습니다(정적 생성자여야 하며 일반 생성자는 작동하지 않습니다).
  • 수정 개체가 다릅니다. const는 클래스 필드와 지역 변수를 모두 수정할 수 있으며, readonly는 클래스 필드만 수정할 수 있습니다.
  • const는 컴파일 타임 상수이며 값은 컴파일 타임에 결정되고, readonly는 런타임 상수이며 값은 런타임에 결정됩니다.
  • const는 기본적으로 static이며 static으로 설정된 경우 readonly를 명시적으로 선언해야 합니다.
  • 참조 유형을 수정할 때와는 다릅니다. const는 값이 null인 문자열이나 기타 참조 유형만 수정할 수 있습니다. readonly는 모든 유형이 될 수 있습니다.
65. nt와 int의 차이점은 무엇입니까?
  • 정수? 이는 널 입력 가능 유형이며 기본값은 널일 수 있습니다.
  • int의 기본값은 0입니다.
  • int?는 참조 유형으로 int boxing을 통해 구현됩니다.
66. 숫자 체계 변환, 정수를 8진수 형식으로 변환
static void Main(string[] args) {
    
    
      int n;
      n =int.Parse(Console.ReadLine());
Console.WriteLine("输入的10进制为:{0}",n);
Console.Write("转换为8进制数为: ");
      d2o(n);
}
static void d2o(int n) {
    
    
     if (n > 7) {
    
    
          d2o(n / 8);
     }
     Console.Write(n%8);
}
67. 200 안에 있는 소수를 찾아보세요.
static void Main(string[] args) {
    
    
    int count = 0;
    for (int i = 1; i < 200; i++) {
    
    //外层循环:要判断的数
        for (int j = 2; j <=i; j++){
    
    
            if (i % j == 0&& i!=j) {
    
    
                 break;
             }
             if (j == i ) {
    
    //结束的条件:最后一个数还没有被整除 
                  count++;
                  Console.WriteLine(i);
             }
        }
    }
    Console.WriteLine(count);
}
68. 양희삼각형 프린트
public static void YHSJ(){
    
    
    int [][]a= new int[7][] ;
    a[0] = new int[1];  //a[0][0]=1;
    a[1] = new int[2] ;
    for (int i = 0; i < 7; i++) {
    
    
        a[i] = new int[i+1] ;  
        a[i][0] =1;
        a[i][i]=1;
        if(i>1) {
    
    //求出中间的数据
    for(int j=1;j
                a[i][j]= a[i-1][j-1]+a[i-1][j];
            }
        }
     }
     for (int i=0; i
         for (int k = 0; k < a.Length-1-i; k++) {
    
    
             Console.Write("");
         }
         for(int j=0;j
             Console.Write(a[i][j] + "");
         }
         Console.WriteLine();
     }
}
69. 중국에는 3일 고기잡이 2일 그물 말리기라는 말이 있는데 2000년 1월 1일부터 어떤 사람이 3일 고기잡이 2일 그물 말리기를 시작했다. 앞으로는 "햇빛에 고기를 잡고 이틀 만에 그물을 말릴 것"입니다. "물고기" 또는 "그물 말리기"
public static void Compute(){
    
    
Console.WriteLine ((DateTime.Now - DateTime.Parse("2000-01-01")).Days%5<3?"打鱼":"晒网");
}
70.객체지향이란 무엇이며 프로세스지향의 차이점은 무엇인가?
  • 객체 지향: 문제를 해결할 때 사물을 객체 개념으로 추상화하고, 문제의 객체를 살펴보고, 이러한 객체에 몇 가지 속성과 메서드를 할당하고, 각 객체가 자신의 메서드를 실행하도록 하고, 최종적으로 문제를 해결합니다.
  • 프로세스 지향: 문제를 해결할 때 이벤트를 함수와 데이터로 풀어낸 다음 이러한 메소드(프로세스)를 일정한 순서로 실행하고, 메소드가 실행되면 문제가 해결됩니다.
  • 프로세스 지향은 객체지향보다 성능이 높지만 객체지향만큼 유지, 재사용, 확장이 쉽지 않습니다.
71. 다섯 가지 기본 원칙
  • 단일 책임 원칙: 클래스의 기능은 단일해야 하며 너무 복잡해서는 안 됩니다. 사람과 마찬가지로 그에게도 너무 많은 일을 할당할 수 없습니다. 그렇지 않으면 매우 바쁘지만 효율성은 떨어지게 됩니다.
  • 개방-폐쇄 원칙: 모듈은 확장성 측면에서는 개방적이지만 변경성 측면에서는 폐쇄적이어야 합니다. 예를 들어 모듈에 원래 서버 측 기능만 있었지만 이제 클라이언트 측 기능을 추가하려는 경우 설계 초기에 서버와 클라이언트를 분리하고 공통 부분을 추상화해야 합니다. 서버측 코드를 수정하지 않고 클라이언트 코드를 추가합니다.
  • Li 스타일 대체 원칙: 하위 클래스는 상위 클래스를 대체할 수 있어야 하며 상위 클래스가 나타날 수 있는 모든 위치에 나타날 수 있어야 합니다. 예를 들어, 연례회의에 참석할 때 일부 직원만 복권에 참여할 수 있도록 허용하는 것이 아니라 회사의 모든 직원이 복권에 참여할 수 있도록 해야 합니다.
  • 종속성 역전 원칙: 구상은 추상에 종속되고 상위 계층은 하위 계층에 종속됩니다. 예를 들어 B는 A보다 하위 모듈이지만 B는 A의 기능을 사용해야 합니다. 이때 B는 A의 구체적인 클래스를 직접 사용할 수 없습니다. 대신 B는 추상 인터페이스를 정의해야 하고 A는 이 추상을 구현해야 합니다. B만 이 추상 인터페이스를 사용하면 종속성 반전이 달성됩니다. B도 A에 대한 종속성에 노출됩니다. 차례로 A는 B가 정의한 추상 인터페이스에 종속됩니다.
  • 인터페이스 분리 원칙: 모듈은 특정 클래스를 통해 강력하게 결합되는 대신 추상 인터페이스를 통해 격리되어야 합니다.
72.깊은 복사와 얕은 복사의 차이점
  • 참조 유형 및 값 유형과 동일
    • 얕은 사본: 참조 사본, 참조 지점이 동시에 동일한 데이터 요소에 있음
    • 딥 카피(Deep Copy): 참조가 달라져 새로운 객체가 생성되며, 데이터가 변경되어도 서로 영향을 미치지 않습니다.
73. 코드에 해당 파일이 존재하는지 확인하고, 존재하지 않는 경우 파일 생성 시:
if (!File.Exists(path))
{
    
    
    File.Create(path);
}
//提示出现 IOException: Sharing violation on path 的错误。
//在创建文件后面加上 Dispose() 函数即可,更改后的代码如下所示
if (!File.Exists(path))
{
    
    
    File.Create(path).Dispose();
}
74. 버블 정렬(손으로 쓴 코드)
public static void BubblingSort(int[]array) 
{
    
    
for (int i = 0; i < array.Length; i++){
    
    
for (int j = array.Length - 1; j > 0; j--){
    
    
if (array[j] < array[i]) {
    
    
int temp = array[j];
array[j] = array[j-1];
array[ j - 1] = temp;
        }
     }
  }
}

75. 클래스 생성자 앞에 static을 추가하면 어떤 오류가 보고되나요?
  • 생성자에 공개 수정 정적 생성자가 있는 경우 "액세스 한정자는 정적 생성자에서 허용되지 않습니다."라고 보고합니다. 수정자가 추가되지 않으면 오류가 보고되지 않습니다.
  • 정적 생성자는 일반적으로 초기화 역할을 합니다.
76.링크드리스트란 무엇인가요? 장점과 단점은 무엇입니까? 용도는 무엇입니까?
  • LinkedList는 이중 연결 리스트로 사용할 수 있는 데이터 구조인 연결 리스트로, 최하위 계층은 연결 리스트로 구현되어 있으며, 서로 참조하는 노드들로 구성된 이중 연결 리스트입니다. 위치에 따라 데이터는 새로운 노드를 형성하고 링크드 리스트의 요소를 변경합니다.해당 두 노드 사이의 참조 관계는 삽입을 완료할 수 있으며 참조 수정을 사용하여 삭제 작업도 완료할 수 있습니다.
    • 장점은 다음과 같습니다. 데이터를 추가, 삭제, 수정하는 것이 매우 편리하며 참조를 직접 수정하면 됩니다.
    • 단점은 특정 데이터를 순회하려면 해당 숫자를 순회할 때까지 처음부터 시작해야 하므로 매우 불편하다는 것입니다.
77.stack, Array, List, Queue, Hashset 및 Dictionary는 각각의 특성, 차이점 및 응용 시나리오를 설명합니다.
  • 스택(Stack)은 선입선출(First In Last Out), 후입선출(Last In First Out)되는 데이터 구조인 스택(Stack)으로, 특정 선형 테이블로 재귀적 시나리오 구현 및 실행 취소 기능 구현에 자주 사용됩니다.
  • 배열(Array)은 연속적인 메모리에 할당되어 마음대로 확장할 수 없는 순차 저장 구조인 배열(Array)로, 데이터 유형이 일관되고, 데이터 삽입이 느리고, 공간을 많이 차지하며, 성능이 뛰어나다. 체하는.
  • 목록은 배열을 사용하여 내부적으로 구현되는 목록이며 제네릭을 구현할 수 있고 언박싱 및 박싱의 위험이 없으며 유형 안전하지만 스레드 안전하지 않으며 공간은 추가 및 삭제된 데이터를 기반으로 동적으로 할당됩니다.
  • LinkedList는 연결된 목록입니다. 메모리의 저장이 반드시 연속적이지는 않습니다. 첨자로 접근할 수 없습니다. 블록을 추가하고 삭제합니다. 노드를 자주 추가하거나 삭제하는 상황에 적합합니다. 쿼리가 느리고 찾기 위해 순회가 필요합니다. 처음부터 하나씩.
  • HashTable은 고유 항목의 정렬되지 않은 목록을 포함하는 해시 모음입니다. 데이터를 빠르게 삽입할 수 있습니다. 제네릭을 지원하지 않는 사전과 유사합니다. 데이터를 저장하고 검색할 때 처리에 해시 값을 사용해야 합니다.
  • Dictionary는 Generic을 구현할 수 있는 사전으로 추가, 삭제, 수정, 검색이 매우 빠르며, Key-Value 쌍의 형태로 데이터를 저장하고, 엔터티를 대체하는 데 사용할 수 있습니다. , 효율성이 크게 향상될 수 있습니다.
  • Queue는 큐입니다. 선입선출, enqueue 및 dequeue의 두 가지 작업이 있습니다. 또한 스레드로부터 안전하지 않습니다. 테이블의 프런트 엔드에서 삭제 작업과 삽입만 허용하는 특수 선형 테이블입니다. 테이블의 백엔드 작업 대기열에 요소가 없으면 빈 대기열이라고 합니다.
78. 큐를 구현하려면 두 개의 스택을 사용하세요
  • 먼저 s1이라는 저장용 Stack을 사용하고 s1의 요소를 s2에 저장한 후 데이터를 반복할 때 연산을 수행할 수 있습니다. s2의 데이터를 꺼내면 선입선출 큐를 구현할 수 있습니다.
79.비트 연산이란 무엇인가요? 사용 예를 들어볼까요?
  • &는 이진 비트 연산에 자주 사용됩니다. 임의의 숫자와 1 사이에서 &를 취해 얻은 결과는 정수의 패리티를 결정하는 것입니다. 마지막 0이 짝수이면 1이면 홀수입니다. . |는 무조건 할당에 사용됩니다. 임의의 숫자 |1은 이진수의 마지막 숫자가 1이 됩니다. 이를 0으로 변경해야 하는 경우 임의의 숫자 | 1을 더한 다음 1을 빼기만 하면 됩니다. ^를 사용하면 됩니다. 크기를 비교합니다. 두 번의 XOR 후에도 동일한 숫자는 변경되지 않으며 간단한 암호화에 사용할 수 있습니다. , 숫자를 키로 설정하고 함께 전송할 데이터를 XOR하여 새 데이터를 가져옵니다. 다시 XOR하여 원본 데이터를 가져옵니다. .
80.포장과 개봉의 차이점은 무엇인가요?
  • 값 유형과 참조 유형의 최종 기본 클래스는 Object입니다.
    • Boxing: 값 유형을 참조 유형으로 변환하고 새 참조를 생성하는 프로세스
    • Unboxing: 참조 유형을 값 유형으로 변환하는 프로세스
    • 박싱 작업: 관리되는 힙이 메모리를 할당하고, 값 유형이 데이터를 복사하고, 개체 주소가 관리되는 힙 개체를 가리킵니다.
    • Unboxing 작업: 개체 참조 주소에 따라 관리되는 힙에서 데이터를 찾고 스택에 데이터를 복사합니다.
  • 박싱 작업을 피하고 새로운 애플리케이션을 생성하려면 먼저 오버로드를 해결하고 두 번째로 제네릭을 사용하는 것이 솔루션입니다.
81. String str = null이고 string str = "", 차이점을 설명하세요.
  • string str = "" 공간을 할당하기 위해 개체를 초기화합니다.
  • string str = null은 공간을 차지하지 않는 null 참조를 나타냅니다.
82. 클래스와 구조체의 유사점과 차이점
  • 같은 점:
    • 구문은 비슷합니다.
  • 차이점:
    • class는 System.Object 클래스에서 상속된 참조 유형이고, struct는 System.ValueType 클래스에서 상속된 값 유형이므로 다형성이 아닙니다. 그러나 System.ValueType은 참조 유형입니다.
    • 기능적 관점에서 클래스는 동작을 나타내며 구조체는 데이터를 저장하는 데 자주 사용됩니다.
    • 클래스는 상속을 지원하고 클래스 및 인터페이스에서 상속할 수 있습니다. 구조체는 상속이 없고 구조체는 클래스에서 상속할 수 없으며 클래스의 기본 클래스로 사용할 수 없지만 구조체는 인터페이스 상속을 지원합니다.
    • 인스턴스화 시 클래스는 반드시 new 키워드를 사용해야 하고, 구조체는 new 키워드를 사용할 필요가 없으며, 구조체는 선언과 동시에 초기화되며 모든 멤버 변수의 기본값은 0 또는 null이다.
83. 구조나 클래스를 선택하는 방법.
  • 스택 공간은 제한되어 있으며 논리적 개체 수가 많은 경우 구조보다 클래스를 만드는 것이 좋습니다.
  • 구조는 점, 직사각형, 색상과 같은 경량 개체를 나타냅니다. 예를 들어, 1000개의 포인트 개체 배열을 선언하면 참조된 각 개체에 대해 추가 메모리가 할당됩니다. 이 경우 구조 비용이 낮아집니다.
  • 클래스는 추상화 및 다중 수준 개체 계층을 나타낼 때 가장 좋은 선택입니다.
  • 유형이 일부 데이터인 대부분의 경우 구조가 최선의 선택입니다.
84.c# 코드 컴파일을 해석합니까?
  • C# 컴파일러를 통해 소스 코드를 관리 코드로 컴파일
  • 생성된 코드를 프로그램 컬렉션으로 결합
  • 공용 언어 런타임 CLR 로드
  • CLR을 통해 어셈블리 실행

추천

출처blog.csdn.net/backlighting2015/article/details/135424739