본문 바로가기
책/Effective C#

Effective C# - Item1 지역변수를 선언할 때는 var를 사용하는 것이 낫다.

by 코딩하는 돼징 2023. 10. 24.
반응형

0. 들어가기 앞서

코딩테스트를 준비하면서 C#에 대해 더 자세히 알고 싶고 효율적으로 코드를 짜고 싶다는 욕심이 생겼다. 어떻게 공부해야할까 하다가 찾아보던 중 Effective 시리즈 책을 알게 되었다.

 

더 나은 개발자로 성장해보자


1. Item1 지역변수를 선언할 때는 var를 사용하는 것이 낫다.

01 지역변수의 타입을 암시적으로 선언하는 것이 좋은 이유

C# 언어가 익명 타입(anonymouse type)을 지원하기 때문이다. 

var를 사용하게 되면 타입 추론이 사용된다. 이는 정적 타이핑(static typing), 동적 타이핑(dynamic typing)과 별개의 개념이다. 타입 추론을 사용게하되면 할당 연산자의 오른쪽 값으로부터 왼쪽 변수의 타입을 추론하여 결정하며 여전히 컴파일 시간에 변수의 정확한 타입이 결정된다.

var number = 10; // number 변수의 타입은 int로 컴파일 시간에 결정된다.

02 정적 타이핑, 동적 타이핑이 뭔가요?

정적 타이핑(Static Typing)

컴파일 시간에 변수의 데이터 타입이 결정되고 그 이후에는 타입이 변경될 수 없다. 이는 코드의 안전성을 높이고 타입 관련 오류를 미리 방지할 수 있다.

int number = 10; 
string name = "piggy";

동적 타이핑(Dynamic Typing)

변수의 데이터 타입이 실행 시간에 결정되며, 변수가 여러가지 타입의 값을 가질 수 있는것을 의미한다. 따라서 변수는 어떤 데이터 타입의 값이든 저장할 수 있다. 

dynamic dynamicVar = 10;
dynamicVar = "Hello";

03 내장 숫자 타입(int, float, double)등을 선언할 때는 명시적으로 타입을 선언하는 편이 낫다.

만약 내장 숫자 타입과 var를 함께 사용하는 경우 float에서 double로의 변환과 같이 확대 변환은 항상 안전하게 수행된다. 반면 long에서 int로의 변환과 같이 축소 변환은 정밀도 손실이 발생할 수 있다. 

var total = 100 * f / 6;

반환 타입에 대한 결과 차이


var를 사용하지 않아서 문제가 생기는 코드 예시

데이터베이스에서 특정 문자열로 시작하는 고객의 이름을 검색하는 코드

public IEnumerable<string> FindCustomersStartingWith1(string start)
{
    IEnumerable<string> q = 
    from c in db.Custromers
    select c.ContactName;
    
    var q2 = q.Where(s => s.StartWith(start));
    return q2;
}

먼저 IQueryable와 IEnumerable대해 알아보자

IQueryable<T>

LINQ to SQL 또는 Entity Framework와 같은 ORM(Object-Relational Mapping) 기술과 함께 사용될 때 데이터베이스 서버에 대한 쿼리를 작성하고, 최적화된 쿼리로 변환하여 데이터베이스 서버에 전송할 수 있다. 이는 데이터베이스에서 필터링이나 정렬을 수행하도록 SQL 쿼리로 변환된다. 또한 IQueryable은 IEnumerable를 상속하므로 IEnumerable에 정의된 LINQ 메서드와 확장 메서드 모두 포함된다.
IEnumerable<T>

LINQ 쿼리를 메모리에서 로컬로 수행하는데 사용된. 쿼리는 데이터베이스에서 모든 데이터를 가져와 메모리에서 필터링, 정렬을 수행한다.


위의 코드에서는 문제가 발생한다.

이는 q를 IEnumerable으로 선언되어서 이는 데이터베이스 쿼리를 데이터베이스 서버에서 수행하는 경우 LINQ쿼리는 실제로 IQueryable을 반환하지만 IEnumerable로 선언했기때문에 IQueryable의 장점들을 못 활용한다.

 

첫번째 쿼리문이 실행되고 필터링되지 않은 연락처 이름이 모두 로컬 컴퓨터로 가져와진다. 이후 두번째 쿼리(Where)문이 차례로 수행되는데 이는 모든 연락처 이름이 로컬로 가져와진 후 메모리에서 필터링된다.


var를 사용해서 문제가 해결된 코드 예시

public IEnumeralbe<string> FindCustomersStartingWith1(string start)
{
    var q = 
    from c in db.Custromers
    select c.ContactName;
    
    var q2 = q.Where(s => s.StartWith(start));
    return q2;
}

var를 사용했으므로 이제 q는 IQueryable<string>으로 추론된다. 첫번째 LINQ쿼리 문장이 실행되면 데이터베이스가 있는 원격지로 아무런 SQL쿼리를 전달하지 않는다. 이는 지연 실행(lazy execution)이라고 한다.


지연 실행이 뭔가요?

지연 실행은 LINQ쿼리가 생성되는 시점에서 데이터베이스에  요청을 즉시 전달하지 않고 실제로 검색하거나 가져오는 메서드가 호출될 때까지 요청을 연기한다.


두번째 쿼리문장을 실행하면 앞서 LINQ쿼리문에 where절을 추가하여 SQL문이 완성된다. 실제로 데이터베이스로의 요청을 발생시키려면 호출자가 IQueryable쿼리를 순회하거나 결과를 가져오는 메서드를 호출하면 필터링된 조건이 SQL쿼리가 원격지로 전달된다. 그러므로 결과에는 조건문에 따라 필터링된 연락처의 이름만 포함된다. 따라서 필터링은 데이터베이스 서버에서 이루어지므로 필요한 데이터만을 효율적으로 가져오고 처리할 수 있다.

 

 

 

 

 

본 게시글은 Effective C#을 읽고 정리하였습니다.

반응형

댓글