# JSON — System.Text.Json📖 שיעור

## מה זה?

שיעור הקודם שמרנו טקסט גולמי לקובץ — נוח לרשימת מחרוזות, אבל מה עם אובייקט `Student` שלם עם כמה שדות? אפשר "להמציא" פורמט טקסט משלנו (`"דנה,25,true"`), אבל אז צריך לכתוב ידנית גם קוד שיודע לפרק אותו חזרה, וכל שינוי במחלקה שובר את הפירוק. JSON פותר את זה: פורמט טקסט **סטנדרטי** שכמעט כל שפת תכנות (וכל API) יודעת לקרוא ולכתוב — `System.Text.Json` הופך אובייקט C# ל-JSON (Serialize) ובחזרה (Deserialize) אוטומטית.

## מילות מפתח שחשוב לזכור

• JSON (JavaScript Object Notation) — פורמט טקסט סטנדרטי לייצוג נתונים מובנים, נתמך כמעט בכל שפה ובכל API

• Serialize — הפיכת אובייקט C# למחרוזת JSON (`JsonSerializer.Serialize`)

• Deserialize — הפיכת מחרוזת JSON בחזרה לאובייקט C# (`JsonSerializer.Deserialize<T>`)

• Property Naming — ברירת המחדל: שם ה-Property ב-JSON זהה לשם ב-C# (`Name`); אפשר להתאים בעזרת attributes אם צריך שם אחר

```csharp
class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
    public List<int> Grades { get; set; }
}

Student student = new Student { Name = "Dana", Age = 20, Grades = new List<int> { 90, 85, 78 } };

// Serialize — object → JSON string
string json = JsonSerializer.Serialize(student);
Console.WriteLine(json);
// {"Name":"Dana","Age":20,"Grades":[90,85,78]}

File.WriteAllText("student.json", json);   // save to file — ties in with the IO lesson
```

```csharp
// Deserialize — JSON string → C# object
string jsonFromFile = File.ReadAllText("student.json");
Student loaded = JsonSerializer.Deserialize<Student>(jsonFromFile);
Console.WriteLine(loaded.Name);   // Dana — a real C# object, not text
```

```csharp
// an entire collection — List<Student> Serialize/Deserialize with the exact same syntax
List<Student> students = new List<Student> { student, new Student { Name = "Avi", Age = 22 } };
string jsonArray = JsonSerializer.Serialize(students, new JsonSerializerOptions { WriteIndented = true });
List<Student> loadedList = JsonSerializer.Deserialize<List<Student>>(jsonArray);
```

## הסבר עיקרי

למה JSON ולא פורמט מומצא — פורמט אישי (כמו CSV פשוט עם פסיקים) שובר בקלות ברגע שערך מכיל פסיק בעצמו, או שצריך לייצג רשימה מקוננת בתוך אובייקט. JSON תומך במבנים מקוננים (`Grades` היא רשימה בתוך `Student`) בצורה סטנדרטית, וכל שפה/כלי יודעים לקרוא אותו בלי המצאה מחדש.

Serialize/Deserialize הם ראי אחד לשני — `JsonSerializer.Serialize(student)` ו-`JsonSerializer.Deserialize<Student>(json)` הם פעולות הפוכות: הראשונה הופכת מופע C# למחרוזת; השנייה בונה מופע C# **חדש** מהמחרוזת, עם אותם ערכים בדיוק. `<Student>` ב-Deserialize הוא חובה — C# צריכה לדעת לאיזה טיפוס לבנות את האובייקט, היא לא "מנחשת" מהתוכן.

Property Naming כברירת מחדל — `System.Text.Json` משתמש בשמות ה-Properties **כמו שהם** (`Name`, `Age`) — לא הופך אוטומטית ל-camelCase כמו שנפוץ ב-JavaScript. אם ה-API/הקובץ שעובדים איתו מצפה לשמות שונים (למשל `student_name`), משתמשים ב-attributes (`[JsonPropertyName("student_name")]`) — לא יידרש כאן, אך שימושי לדעת שקיים.

## יתרונות

JSON הוא סטנדרט אוניברסלי — כמעט כל API/שפה יודעים לקרוא ולכתוב אותו; `System.Text.Json` מובנה ב-.NET, בלי צורך בחבילה חיצונית; תומך במבנים מקוננים (אובייקטים בתוך אובייקטים, רשימות) בצורה טבעית.

## חסרונות

JSON לא תומך בכל טיפוס C# ישירות (למשל `DateTime` נשמר כמחרוזת בפורמט מסוים, לא כטיפוס מקורי); Deserialize על JSON לא-תואם למחלקת היעד (שדה חסר, טיפוס שגוי) עלול לזרוק חריגה או להשאיר ערכי ברירת מחדל בלי אזהרה ברורה.

## נקודות חשובות

• Serialize = אובייקט → JSON; Deserialize = JSON → אובייקט, עם `<T>` מפורש

• JSON תומך במבנים מקוננים (אובייקטים, רשימות) בצורה סטנדרטית

• שמות Properties ב-JSON תואמים כברירת מחדל לשמות ב-C# (`Name`, לא `name`)

• JSON הוא הבסיס לתקשורת עם כמעט כל REST API — יופיע שוב ביחידת ASP.NET Core

## טעויות נפוצות

• לשכוח `<Student>` ב-`Deserialize<T>` — הקומפיילר לא יודע לאיזה טיפוס לבנות בלי זה

• להניח שכל JSON חיצוני יתאים אוטומטית למחלקת C# בלי לבדוק שמות שדות והתאמת טיפוסים

• לנסות Serialize על מבנה מעגלי (אובייקט שמצביע על עצמו) — עלול לזרוק חריגה על עומק רקורסיה

## סיכום

JSON הוא פורמט טקסט סטנדרטי לייצוג נתונים מובנים, נתמך כמעט בכל שפה ו-API. `JsonSerializer.Serialize` הופך אובייקט C# למחרוזת JSON; `JsonSerializer.Deserialize<T>` הופך מחרוזת JSON בחזרה לאובייקט C# מהטיפוס שצוין. שילוב עם שיעור ה-IO (`File.WriteAllText`/`ReadAllText`) מאפשר לשמור ולטעון אובייקטים שלמים לדיסק בפורמט סטנדרטי, במקום פורמט טקסט מומצא ושברירי.

## דוקומנטציה רשמית

[Microsoft Learn — System.Text.Json overview](https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/overview)

---

## תרגילים

### תרגיל 1 — Serialize/Deserialize בסיסי

**המשימה:** צרו מחלקת `Product` עם `Name` ו-`Price`, המירו מופע ל-JSON עם `Serialize`, הדפיסו אותו, ואז המירו אותו בחזרה לאובייקט עם `Deserialize<Product>`.

**בדיקה:** האובייקט אחרי Deserialize מכיל בדיוק את אותם ערכים כמו המקורי.

### תרגיל 2 — שמירה וטעינה מקובץ

**המשימה:** שמרו `List<Product>` לקובץ `products.json` עם Serialize+File.WriteAllText, ואז בהרצה נפרדת (או קוד נפרד) טענו אותה בחזרה עם File.ReadAllText+Deserialize.

**בדיקה:** הרשימה שנטענה מהקובץ זהה בתוכן לרשימה המקורית שנשמרה.

---

## פרויקט מסכם

**המשימה:** בנו "מערכת הגדרות אפליקציה" ששומרת וטוענת הגדרות מ-JSON.

**דרישות:**
1. `class AppSettings` עם לפחות 4 שדות (למשל `Theme`, `Language`, `NotificationsEnabled`, `MaxItemsPerPage`)
2. פונקציה `SaveSettings(AppSettings settings)` ששומרת ל-`settings.json` עם `WriteIndented = true`
3. פונקציה `LoadSettings()` שטוענת מהקובץ אם קיים, ומחזירה הגדרות ברירת מחדל אם הקובץ לא קיים (`File.Exists`)

**בדיקה:** שמירת הגדרות, שינוי ידני של הקובץ (למשל עריכה ב-Notepad), וטעינה חוזרת מחזירה את הערכים המעודכנים; מחיקת הקובץ וטעינה מחזירה הגדרות ברירת מחדל בלי לקרוס.

## מה בפרק הבא

בפרק הבא — **LINQ, חלק א'**: איך מסננים וממיינים אוספים בשורה אחת עם `Where`/`Select`/`OrderBy`, במקום לולאות `foreach` ידניות עם דגלים ומשתני עזר.
