0Pricing
C# Academy · บทเรียน

เครื่องมือเจเนอริกที่นำกลับมาใช้ซ้ำได้

สร้างตัวช่วยขนาดเล็กที่นำกลับมาใช้ซ้ำได้: การตรวจสอบ Guard ตัวเปรียบเทียบความเท่ากันตามคีย์ การจดจำผลลัพธ์สำหรับฟังก์ชันบริสุทธิ์ และ Result แบบง่าย

เครื่องมือเจเนอริกที่นำกลับมาใช้ซ้ำได้ เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 3 บทเรียน

แผนชุดเครื่องมือ

เป้าหมาย: รวบรวมตัวช่วยขนาดเล็กที่นำกลับมาใช้ซ้ำได้ในหลายโครงการ

  • การตรวจสอบ Guard สำหรับอาร์กิวเมนต์
  • ตัวเปรียบเทียบตามคีย์สำหรับความเท่ากัน
  • จดจำผลลัพธ์ของฟังก์ชันบริสุทธิ์
  • Result<T> สำหรับกระบวนการสำเร็จ/ข้อผิดพลาด

การตรวจสอบ Guard

รวมการตรวจสอบอาร์กิวเมนต์ไว้ในคลาส 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 กับฟังก์ชันบริสุทธิ์
  • เขียนการทดสอบหน่วยอย่างรวดเร็วสำหรับตัวช่วยแต่ละตัว

ประโยชน์ของตัวเปรียบเทียบตามคีย์

ตรวจสอบสั้น ๆ: ตัวเปรียบเทียบความเท่ากันตามคีย์สำหรับชนิด T ช่วยให้คุณทำอะไรได้บ้าง

สรุปทบทวน

สรุปทบทวน: นำเครื่องมือขนาดเล็กกลับมาใช้ซ้ำ ได้แก่ Guard สำหรับข้อมูลขาเข้า KeyEqualityComparer สำหรับความเท่ากัน Memo สำหรับฟังก์ชันบริสุทธิ์ และ Result<T> สำหรับผลลัพธ์ที่ระบุอย่างชัดเจน

คำถามที่พบบ่อย

บทเรียน “เครื่องมือเจเนอริกที่นำกลับมาใช้ซ้ำได้” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “เครื่องมือเจเนอริกที่นำกลับมาใช้ซ้ำได้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 3 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “เครื่องมือเจเนอริกที่นำกลับมาใช้ซ้ำได้”

สร้างตัวช่วยขนาดเล็กที่นำกลับมาใช้ซ้ำได้: การตรวจสอบ Guard ตัวเปรียบเทียบความเท่ากันตามคีย์ การจดจำผลลัพธ์สำหรับฟังก์ชันบริสุทธิ์ และ Result แบบง่าย คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน

บทเรียน “เครื่องมือเจเนอริกที่นำกลับมาใช้ซ้ำได้” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. unmanaged, notnull, new() (จำลองใน C# 6)
  2. คณิตศาสตร์แบบเจเนอริก (ภาพรวม) และแอตทริบิวต์แบบเจเนอริก (เมื่อเหมาะสม)
  3. เครื่องมือเจเนอริกที่นำกลับมาใช้ซ้ำได้
← กลับไปที่ C# Academy