0Pricing
C# Academy · 강의

재사용 가능한 제네릭 유틸리티

작고 재사용 가능한 도우미를 만듭니다. Guard 검사, 키 기반 같음 비교기, 순수 함수용 메모이제이션, 간단한 Result 를 다룹니다.

재사용 가능한 제네릭 유틸리티은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 3개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 3개의 강의가 포함되어 있습니다.

도구 모음 계획

목표: 여러 프로젝트에서 재사용할 수 있는 작은 도우미를 모읍니다.

  • 인수를 위한 Guard 검사
  • 동등성 비교를 위한 키 기반 비교기
  • 순수 함수를 메모이제이션하기
  • 성공 및 오류 흐름을 위한 Result<T>

가드 검사

작은 Guard 클래스에서 인수 검증을 한곳에 관리하고, 메서드 시작 부분에서 호출합니다.

using System;

public static class Guard
{
  public static T NotNull<T>(T value, string name) where T : class
  {
    if (value == null) throw new ArgumentNullException(name);
    return value;
  }

  public static string NotNullOrEmpty(string value, string name)
  {
    if (string.IsNullOrEmpty(value)) throw new ArgumentException("must not be null or empty", name);
    return value;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    // OK
    string name = Guard.NotNullOrEmpty("Ada", "name");
    Console.WriteLine("Hello, " + name);

    // Uncomment to see guard throw:
    // Guard.NotNull<string>(null, "input");
  }
}

키 기반 비교기

모델의 Equals/GetHashCode를 건드리지 않고 키(예: 식별자)를 기준으로 복잡한 객체를 비교합니다.

using System;
using System.Collections.Generic;

public sealed class KeyEqualityComparer<T, TKey> : IEqualityComparer<T>
{
  private readonly Func<T, TKey> _keySelector;
  private readonly IEqualityComparer<TKey> _keyComparer;

  public KeyEqualityComparer(Func<T, TKey> keySelector)
    : this(keySelector, EqualityComparer<TKey>.Default) {}

  public KeyEqualityComparer(Func<T, TKey> keySelector, IEqualityComparer<TKey> keyComparer)
  {
    if (keySelector == null) throw new ArgumentNullException("keySelector");
    if (keyComparer == null) throw new ArgumentNullException("keyComparer");
    _keySelector = keySelector;
    _keyComparer = keyComparer;
  }

  public bool Equals(T x, T y)
  {
    if (object.ReferenceEquals(x, y)) return true;
    if ((object)x == null || (object)y == null) return false;
    return _keyComparer.Equals(_keySelector(x), _keySelector(y));
  }

  public int GetHashCode(T obj)
  {
    if ((object)obj == null) return 0;
    TKey key = _keySelector(obj);
    return key == null ? 0 : _keyComparer.GetHashCode(key);
  }
}

public sealed class User
{
  public int Id;
  public string Name;
}

public class Program
{
  public static void Main(string[] args)
  {
    List<User> list = new List<User>();
    list.Add(new User { Id = 1, Name = "Ada" });
    list.Add(new User { Id = 1, Name = "Ada Lovelace" }); // same Id -> considered equal
    list.Add(new User { Id = 2, Name = "Alan" });

    // Deduplicate by Id using a HashSet with our comparer
    HashSet<User> set = new HashSet<User>(new KeyEqualityComparer<User,int>(delegate(User u) { return u.Id; }));
    foreach (User u in list) set.Add(u);

    Console.WriteLine("Unique by Id = " + set.Count); // 2
  }
}

메모이제이션 도우미

메모이제이션은 순수 함수의 결과를 캐시합니다. 같은 입력으로 호출을 반복할 때 사용합니다.

using System;
using System.Collections.Generic;

public static class Memo
{
  // Wrap a pure function f: K -> V with a simple cache
  public static Func<TKey, TValue> Memoize<TKey, TValue>(Func<TKey, TValue> f)
  {
    if (f == null) throw new ArgumentNullException("f");
    Dictionary<TKey, TValue> cache = new Dictionary<TKey, TValue>();
    return delegate(TKey key)
    {
      TValue v;
      if (cache.TryGetValue(key, out v)) return v;
      v = f(key);
      cache[key] = v;
      return v;
    };
  }
}

public class Program
{
  static int SlowSquare(int x)
  {
    // Simulate work
    System.Threading.Thread.Sleep(100);
    return x * x;
  }

  public static void Main(string[] args)
  {
    Func<int,int> fast = Memo.Memoize<int,int>(SlowSquare);

    var t1 = DateTime.UtcNow; Console.WriteLine(fast(12));
    var t2 = DateTime.UtcNow; Console.WriteLine(fast(12)); // from cache
    var dt1 = (t2 - t1).TotalMilliseconds;

    var t3 = DateTime.UtcNow; Console.WriteLine(fast(12)); // from cache again
    var t4 = DateTime.UtcNow; var dt2 = (t4 - t3).TotalMilliseconds;

    Console.WriteLine("First vs cached ms: " + dt1 + " / " + dt2);
  }
}

Result<T> 래퍼

최소한의 Result<T> 형식을 사용하면 성공과 오류를 명시적으로 표현할 수 있어 출력하거나 테스트하기 쉽습니다.

using System;

public enum ResultKind { Ok, Error }

public sealed class Result<T>
{
  public ResultKind Kind;
  public T Value;            // valid when Ok
  public string Error;       // valid when Error

  private Result() {}

  public static Result<T> Ok(T value)
  {
    Result<T> r = new Result<T>();
    r.Kind = ResultKind.Ok;
    r.Value = value;
    r.Error = null;
    return r;
  }

  public static Result<T> Fail(string error)
  {
    if (string.IsNullOrEmpty(error)) throw new ArgumentException("error");
    Result<T> r = new Result<T>();
    r.Kind = ResultKind.Error;
    r.Error = error;
    r.Value = default(T);
    return r;
  }

  public override string ToString()
  {
    return Kind == ResultKind.Ok ? "OK: " + (Value == null ? "null" : Value.ToString())
                                 : "ERROR: " + Error;
  }
}

public class Program
{
  static Result<int> ParsePositiveInt(string s)
  {
    int n;
    if (!Int32.TryParse(s, out n)) return Result<int>.Fail("not a number");
    if (n <= 0) return Result<int>.Fail("must be > 0");
    return Result<int>.Ok(n);
  }

  public static void Main(string[] args)
  {
    Console.WriteLine(ParsePositiveInt("12"));
    Console.WriteLine(ParsePositiveInt("-1"));
    Console.WriteLine(ParsePositiveInt("x"));
  }
}

실용적인 팁

팁:

  • 도우미는 작고 목적을 분명하게 유지합니다.
  • 이름을 명확하게 지정합니다: Guard, KeyEqualityComparer, Memo.
  • 제약 조건과 사용 시점(Memo에는 순수 함수 사용)을 문서화합니다.
  • 각 도우미마다 간단한 단위 테스트를 작성합니다.

키 비교기의 장점

빠른 확인: 키 기반 IEqualityComparer<T>를 사용하면 무엇을 할 수 있습니까?

복습

복습: 작은 도구를 재사용합니다. 입력에는 Guard, 동등성 비교에는 KeyEqualityComparer, 순수 함수에는 Memo, 명시적인 결과에는 Result<T>를 사용합니다.

자주 묻는 질문

“재사용 가능한 제네릭 유틸리티” 강의는 무료인가요?

네 — “재사용 가능한 제네릭 유틸리티” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 3개의 강의가 포함되어 있습니다.

“재사용 가능한 제네릭 유틸리티”에서 뭘 배우나요?

작고 재사용 가능한 도우미를 만듭니다. Guard 검사, 키 기반 같음 비교기, 순수 함수용 메모이제이션, 간단한 Result 를 다룹니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C# Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 3개 중 3번째 강의입니다.

“재사용 가능한 제네릭 유틸리티” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. unmanaged, notnull, new()(C# 6 에뮬레이션)
  2. 제네릭 수학(개요)과 제네릭 특성(관련되는 경우)
  3. 재사용 가능한 제네릭 유틸리티
← C# Academy(으)로 돌아가기