닷넷 컬렉션 동작의 이해

ToArray()와 ToList()의 실행 원리

ToArray와 ToList함수는 파라미터로 받은 enumerator 인터페이스를 ICollection 인터페이스로 타입 변경을 시도하여 ICollection의 CopyTo 함수를 사용하도록 한다.

컬렉션 인터페이스를 획득할 수 없는 경우, enumerator의 MoveNext를 사용하여 동적으로 배열의 크기를 늘리면서 아이템을 (레퍼런스) 복사한다.

컬렉션 인터페이스에서 새로운 컬렉션을 생성하는 경우, 컬렉션을 복사하는 과정에서 배열의 크기가 동적으로 변경되지 않도록 하기 때문에 불필요한 메모리 할당과 해제를 억제할 수 있다

[1].

see also

How operates ToArray

닷넷 컬렉션 인터페이스

제너릭 버전이 아닌 컬렉션 인터페이스는 아이템을 추가, 삭제할 수 있는 함수가 노출되어 있지 않아서 컬렉션을 수정할 수는 없지만, CopyTo와 GetEnumerator 함수로부터 새로운 컬렉션을 생성할 수 있다.

반면, 제너릭 콜렉션 인터페이스에는 Add, Remove, Clear 같이 컬렉션을 변경할 수 있는 함수들이 정의되어 있어서, 객체의 함수나 속성의 타입으로 컬렉션 인터페이스를 노출하면 객체가 상태가 임의로 변경될 수 있다.

객체에서 제너릭 콜렉션 인터페이스를 구현했다면 Enumerable 인터페이스로부터 타입 캐스팅으로 재너릭 콜렉션 인터페이스를 획득할 수 있으므로, 인터페이스 타입으로만으로는 객체의 아이템을 보호할 수 없다.

Immutable 컬렉션

읽기 전용 컬렉션 인터페이스

IReadOnlyCollection애는 Count 속성만 정의하고 있고, 정작 컬렉션의 아이템을 조회하기 위한 함수는 정의하고 있지 않다.

Count 속성
제너릭 읽기 전용 컬렉션은 카운트 속성만 정의하는데, enumerator는 메모리 이외에도 소켓, 파일, 데이터베이스 등 전체 데이터를 순환하는 비용이 훨씬 큰 데이터 소스로부터 데이터를 가져오는 경우도 있으므로 Count와 같은 전체 컬렉션의 데이터를 조회하는 속성을 사용할 때는 주의해야 한다.


읽기 전용 컬렉션에서 아이템을 조회하기 위해서는 IReadOnlyDictuonary, IReadOnlyList와 같이 컬렉션의 타입까지 노출하는 인터페이스를 사용해야 한다.

Immutable 컬렉션

읽기 전용 컬렉션과 별개로 닷넷은 배열로부터 생성한 새 컬럭션 객체는 동적으로 읽기 전용으로 만든다.

즉, 컬렉션 인터페이스의 Add, Remove, Clear를 호출하면 NotSupportedException이 발생해서, 컬렉션을 수정할 수는 없고 오직 참조만을 할 수 있다.

배열이 아닌 컬렉션들은 AsReadOnly() 메소드로 읽기 전용으로 동작하는 컬렉션을 생성할 수 있다.

결론

ToArray와 ToList 함수는 새로운 컬렉션을 생성할 때, 가능하면 불필요한 메모리의 할당이 발생하지 않도록 구현되어 있다.

컬렉션을 외부에 노출할 때는 컬렉션을 복사할 때의 효율성을 감안해서, 특정 유형의 컬렉션 인터페이스를 노출할 필요 없이 IEnumerable 인터페이스를 노출해도 된다.

단, 배열이 아닌 컬렉션의 경우 AsReadOnly 함수를 사용해서, 객체에서 노출한 컬렉션에 의해 객체의 상태가 임의로 변경되는 것은 막을 필요가 있다.


  1. List와 달리 배열 타입은 버퍼의 크기와 배열의 길이가 일치하도록, 복사한 객체의 크기 만큼의 새 배열을 생성한 뒤 다시 배열을 복사하는 과정이 추가된다.

Comments are closed.

Website Built by WordPress.com.

Up ↑