제네릭을 사용하면 데이터 형식에 의존하지 않는 클래스를 작성할 수 있어, 코드 재사용성과 타입 안정성을 높일 수 있다.
람다식(Lambda Expression)이 무엇인지 설명해주세요.
(input-parameters) => expression // 식 람다
(input-parameters) => { <sequence-of-statements> } // 문 람다
Func<int, int> square = x => x * x; // 식 람다
Action<string> greet = name => { Console.WriteLine("Hello, " + name); }; // 문 람다
익명 메소드를 만들기 위해 람다 선언 연산자 (⇒)를 사용하는 식으로, 식이 본문으로 포함된 식 람다, 문 블록이 본문으로 포함된 문 람다가 있다.
LINQ란 무엇인가요?
int[] numbers = { 1, 2, 3, 4, 5 };
// 쿼리문 형태
var evenNumbers = from num in numbers
where num % 2 == 0
select num;
// 람다식 형태
var evenNumbersLambda = numbers.Where(num => num % 2 == 0);
c# 언어에서 쿼리 기능을 사용하는 것으로 데이터를 빠르고 편리하게 추출 및 처리할 수 있다.
Linq == (SQL + 람다식)
Linq는 데이터 그룹화가 강점이다.
리플렉션(Reflection)이 뭔지, 사용을 해봤다면 어떤 이유에서 사용했는지 설명해주세요.
정의
리플렉션은 프로그램 실행 중 메소드, 프로퍼티 등 인스턴스의 데이터 타입 정보를 확인하거나 검사하려는 경우 사용되는 기능으로 컴파일 시 알 수 없었던 타입이나 멤버들을 찾아내고 사용할 수 있게 해준다.
사용
using System;
using System.Reflection;
public class Person
{
public string Name { get; set; }
private int age;
public Person(string name, int age)
{
Name = name;
this.age = age;
}
private void DisplayAge()
{
Console.WriteLine($"Age: {age}");
}
}
public class ReflectionExample
{
public static void Main(string[] args)
{
// 타입 정보 가져오기
Type personType = typeof(Person);
// 생성자 호출
object personInstance = Activator.CreateInstance(personType, "John", 30);
// 필드 및 속성 정보 가져오기
PropertyInfo nameProperty = personType.GetProperty("Name");
FieldInfo ageField = personType.GetField("age", BindingFlags.NonPublic | BindingFlags.Instance);
// 값 설정 및 가져오기
nameProperty.SetValue(personInstance, "Jane");
Console.WriteLine(nameProperty.GetValue(personInstance)); // Output: Jane
// 비공개 메서드 호출
MethodInfo displayAgeMethod = personType.GetMethod("DisplayAge", BindingFlags.NonPublic | BindingFlags.Instance);
displayAgeMethod.Invoke(personInstance, null); // Output: Age: 30
}
}
데이터 타입의 정보(예: 필드, 속성, 메서드)를 확인하거나, 동적으로 객체의 멤버/필드에 접근하고 수정할 수 있다.
리플렉션의 단점에 대해 설명해주세요.
성능 오버헤드
리플렉션은 런타임에 타입 정보를 조회하고 조작하기 때문에 성능에 부담이 될 수 있습니다.
타입 안전성 저하
컴파일 시에 타입 체크가 이루어지지 않기 때문에 런타임 오류가 발생할 수 있습니다.
복잡성 증가
리플렉션을 사용하는 코드는 일반적으로 더 복잡하고 유지보수가 어려울 수 있습니다.
using System;
using System.Collections.Generic;
public class Box<T>
{
public T Value { get; set; }
public void DisplayValue()
{
Console.WriteLine($"Value: {Value}");
}
}
class Program
{
static void Main(string[] args)
{
Box<int> intBox = new Box<int> { Value = 123 };
Box<string> strBox = new Box<string> { Value = "Hello, World" };
Box<DateTime> dateBox = new Box<DateTime> { Value = DateTime.Now };
intBox.DisplayValue();
strBox.DisplayValue();
dateBox.DisplayValue();
}
}
다음 코드에서 제네릭을 사용한 부분을 식별하고, 해당 코드가 제네릭을 사용하지 않았을 때 발생할 수 있는 문제점에 대해 설명하세요.
Box 클래스가 제네릭을 사용한 제네릭 클래스이다.
제네릭을 사용하지 않는다면 value의 데이터 타입이 변할 때마다 데이터 타입만 다른 중복 클래스를 만들어줘야한다.
아래 코드가 어떤 기능을 하는지, 어떤 방식으로 동작하는지 간단하게 설명해주세요.
public static T Max<T>(T a, T b) where T : IComparable<T> { return a.CompareTo(b) > 0 ? a : b; }
IComparable를 상속받는 데이터 타입의 입력 값 둘 중 큰 변수를 반환하는 정적 일반화 함수이다.
제네릭을 사용하여 어떤 데이터 타입이든 대응가능하게 작성하여 코드 재사용성과 타입 안정성을 높일 수 있다.