{
char[] chars = text.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
public static int CountWords(string text)
{
if (string.IsNullOrEmpty(text))
return 0;
return text.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length;
}
// متد نمونه
public string AddExclamation(string text)
{
return text + "!!!";
}
}
// استفاده
string reversed = StringHelper.Reverse("hello");
Console.WriteLine(reversed); // olleh
int wordCount = StringHelper.CountWords("Hello world from C#");
Console.WriteLine(wordCount); // 4
// برای متد نمونه باید شیء بسازیم
StringHelper helper = new StringHelper();
string excited = helper.AddExclamation("Hello");
Console.WriteLine(excited); // Hello!!!
---
✅ تمرین نهایی درس یازدهم
برنامهای بنویسید که:
1. کلاس Product با فیلدهای نمونه (Name, Price) و فیلد استاتیک (TotalProducts, TotalValue)
2. متد نمونه ShowInfo()
3. متد استاتیک ShowSummary()
4. هر بار یک محصول جدید ساخته شود، TotalProducts و TotalValue بهروز شود
csharp
using System;
class Product
{
// فیلدهای نمونه
public string Name { get; set; }
public double Price { get; set; }
// فیلدهای استاتیک
private static int totalProducts = 0;
private static double totalValue = 0;
// سازنده
public Product(string name, double price)
{
Name = name;
Price = price;
totalProducts++;
totalValue += price;
Console.WriteLine($"Product '{name}' created with price {price:C}");
}
// متد نمونه
public void ShowInfo()
{
Console.WriteLine($"Product: {Name}, Price: {Price:C}");
}
// متد استاتیک برای نمایش خلاصه
public static void ShowSummary()
{
Console.WriteLine("\n=== Store Summary ===");
Console.WriteLine($"Total Products: {totalProducts}");
Console.WriteLine($"Total Inventory Value: {totalValue:C}");
Console.WriteLine($"Average Price: {(totalProducts > 0 ? totalValue / totalProducts : 0):C}");
}
// متد استاتیک برای محاسبه تخفیف
public static double ApplyDiscount(double price, double discountPercent)
{
return price * (1 - discountPercent / 100);
}
}
class Program
{
static void Main()
{
// ساختن محصولات
Product p1 = new Product("Laptop", 15000000);
Product p2 = new Product("Mouse", 250000);
Product p3 = new Product("Keyboard", 850000);
Product p4 = new Product("Monitor", 5500000);
Console.WriteLine();
// نمایش اطلاعات هر محصول
p1.ShowInfo();
p2.ShowInfo();
p3.ShowInfo();
p4.ShowInfo();
// نمایش خلاصه فروشگاه
Product.ShowSummary();
// استفاده از متد استاتیک تخفیف
double discountedPrice = Product.ApplyDiscount(15000000, 15);
Console.WriteLine($"\nLaptop with 15% discount: {discountedPrice:C}");
Console.WriteLine("\nPress Enter to exit...");
Console.ReadLine();
}
}
---
📌 جمعبندی درس یازدهم
مفهوم مثال دسترسی
فیلد نمونه public string Name از طریق شیء
فیلد استاتیک public static int Count از طریق کلاس
متد نمونه public void Show() از طریق شیء
متد استاتیک public static void Calc() از طریق کلاس
کلاس استاتیک static class Utility نمیتوان شیء ساخت
قوانین مهم:
1. متد استاتیک نمیتواند به عضو نمونه دسترسی داشته باشد
csharp
static void Method() { Name = "Ali"; } // ❌ اگر Name نمونه باشد
2. متد نمونه میتواند به عضو استاتیک دسترسی داشته باشد
csharp
void Method() { Count = 10; } // ✅ اگر Count استاتیک باشد
`3. کلاس استاتیک فقط عضو استاتیک میتواند داشته باشد --- 🧪 تمرین برای شما 1. کلاس Counter بسازید با: · فیلد استاتیک totalCount
· متد استاتیک Increment()
· متد استاتیک GetCount()
· از چند جا صدا بزنید و نتیجه را ببینید
2. کلاس Configuration بسازید با:
· فیلدهای استاتیک: AppName, Version, Theme
· سازنده استاتیک برای مقداردهی اولیه
3. برنامهای بنویسید که تعداد دفعاتی که یک متد صدا زده شده را با فیلد استاتیک بشمارد
---
اگر این درس را کامل فهمیدید، بگویید تا درس دوازدهم (Enum و Struct) را شروع کنیم. سوالی بود بپرسید.
خیلی خوب، رسیدیم به درس دوازدهم: Enum (شمارندهها) و Struct (ساختارها).
این دو نوع داده به شما کمک میکنند کد خواناتر و منظمتری بنویسید.
یک پروژه جدید بسازید (dotnet new console) و کدها را همراه من بنویسید و اجرا کنید.
---
📘 درس دوازدهم – Enum و Struct
🎯 سرفصلها:
1. Enum چیست و چرا نیاز داریم؟
2. تعریف و استفاده از Enum
3. مقداردهی عددی به Enum
4. تبدیل Enum به عدد و متن
5. Struct چیست؟
6. تفاوت Struct با Class
7. استفاده از Struct
8. تمرین جامع
---
⏱️ قسمت 1: Enum چیست؟
Enum = مجموعهای از ثابتهای نامدار
بدون Enum (کد بد):
csharp
int userRole = 1; // 1=admin, 2=user, 3=guest
if (userRole == 1)
{
Console.WriteLine("Welcome Admin");
}
// مشکل: عدد 1 یعنی چه؟ یادم میرود!
با Enum (کد خوب):
csharp
enum UserRole
{
Admin,
User,
Guest
}
UserRole role = UserRole.Admin;
if (role == UserRole.Admin)
{
Console.WriteLine("Welcome Admin");
}
---
⏱️ قسمت 2: تعریف و استفاده از Enum
csharp
// تعریف Enum (معمولاً بیرون از کلاس)
enum Days
{
Saturday,
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday
}
enum Status
{
Pending,
Approved,
Rejected,
Shipped
}
// استفاده
Days today = Days.Wednesday;
Status orderStatus = Status.Approved;
Console.WriteLine($"Today is: {today}");
Console.WriteLine($"Order status: {orderStatus}");
// استفاده در شرط
if (orderStatus == Status.Approved)
{
Console.WriteLine("Your order is approved!");
}
---
⏱️ قسمت 3: مقداردهی عددی به Enum
به طور پیشفرض، اعضای Enum از 0 شروع میشوند.
csharp
enum Priority
{
Low = 1, // مقدار 1
Medium = 2, // مقدار 2
High = 3, // مقدار 3
Urgent = 10 // مقدار 10
}
enum Color
{
Red = 10,
Green = 20,
Blue = 30
}
// استفاده
Priority taskPriority = Priority.High;
Console.WriteLine(taskPriority); // High
Console.WriteLine((int)taskPriority); // 3
Priority urgent = Priority.Urgent;
Console.WriteLine((int)urgent); // 10
مقداردهی خودکار:
csharp
enum ErrorCode
{
None = 0,
NotFound = 100,
Unauthorized = 101,
ServerError = 500
}
---
⏱️ قسمت 4: تبدیل Enum به عدد و متن
csharp
enum Season
{
Spring = 1,
Summer = 2,
Autumn = 3,
Winter = 4
}
// Enum به عدد
Season current = Season.Summer;
int seasonNumber = (int)current;
Console.WriteLine(seasonNumber); // 2
// عدد به Enum
int input = 3;
Season parsedSeason = (Season)input;
Console.WriteLine(parsedSeason); // Autumn
// Enum به متن
string seasonName = current.ToString();
Console.WriteLine(seasonName); // Summer
// متن به Enum
string userInput = "Winter";
Season selected = (Season)Enum.Parse(typeof(Season), userInput);
Console.WriteLine(selected); // Winter
// روش امن برای تبدیل (بدون خطا)
if (Enum.TryParse("Spring", out Season result))
{
Console.WriteLine($"Parsed: {result}");
}
---
⏱️ قسمت 5: Struct چیست؟
Struct = یک نوع مقدار (Value Type) که دادههای کوچک را نگهداری میکند.
تعریف Struct:
csharp
struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
public double DistanceFromOrigin()
{
return Math.Sqrt(X * X + Y * Y);
}
}
// استفاده
Point p1;
p1.X = 10;
p1.Y = 20;
Point p2 = new Point(5, 7);
Point p3 = new Point(); // تمام فیلدها پیشفرض (0)
Console.WriteLine($"p1: ({p1.X}, {p1.Y})");
Console.WriteLine($"p2: ({p2.X}, {p2.Y})");
Console.WriteLine($"p3: ({p3.X}, {p3.Y})");
Console.WriteLine($"Distance: {p2.DistanceFromOrigin():F2}");
---
⏱️ قسمت 6: تفاوت Struct با Class (خیلی مهم)
ویژگی Class Struct
نوع Reference Type (ارجاعی) Value Type (مقداری)
مکان در حافظه Heap Stack
ارثبری دارد ندارد
سازنده پیشفرض دارد نمیتوان داشت
مقایسه مرجع را مقایسه میکند مقدار را مقایسه میکند
سرعت برای داده کوچک کندتر سریعتر
استفاده برای دادههای بزرگ دادههای کوچک (کمتر از 16 بایت)
`csharp // کلاس (Reference Type) class PointClass { public int X { get; set; } public int Y { get; set; } public PointClass(int x, int y) { X = x; Y = y; } }
// Struct (Value Type)
struct PointStruct
{
public int X { get; set; }
public int Y { get; set; }
public PointStruct(int x, int y)
{
X = x;
Y = y;
}
}
// تفاوت در عمل
PointClass c1 = new PointClass(5, 5);
PointClass c2 = c1; // c2 به همان شیء اشاره میکند
c2.X = 10;
Console.WriteLine($"c1.X = {c1.X}"); // 10 (تغییر کرد!)
PointStruct s1 = new PointStruct(5, 5);
PointStruct s2 = s1; // کپی از مقدار
s2.X = 10;
Console.WriteLine($"s1.X = {s1.X}"); // 5 (تغییر نکرد!)
---
⏱️ قسمت 7: مثالهای کاربردی Struct
Struct برای مختصات RGB:
csharp
struct RGBColor
{
public byte Red;
public byte Green;
public byte Blue;
public RGBColor(byte red, byte green, byte blue)
{
Red = red;
Green = green;
Blue = blue;
}
public string GetHexCode()
{
return $"#{Red:X2}{Green:X2}{Blue:X2}";
}
public string GetName()
{
if (Red == 255 && Green == 0 && Blue == 0) return "Red";
if (Red == 0 && Green == 255 && Blue == 0) return "Green";
if (Red == 0 && Green == 0 && Blue == 255) return "Blue";
if (Red == 255 && Green == 255 && Blue == 255) return "White";
if (Red == 0 && Green == 0 && Blue == 0) return "Black";
return "Custom Color";
}
}
// استفاده
RGBColor red = new RGBColor(255, 0, 0);
RGBColor custom = new RGBColor(128, 200, 50);
Console.WriteLine(red.GetHexCode()); // #FF0000
Console.WriteLine(red.GetName()); // Red
Console.WriteLine(custom.GetHexCode()); // #80C832
Console.WriteLine(custom.GetName()); // Custom Color
Struct برای محدوده (Range):
csharp
struct Range
{
public int Start;
public int End;
public Range(int start, int end)
{
if (start > end)
throw new ArgumentException("Start must be less than or equal to End");
Start = start;
End = end;
}
public int Length => End - Start + 1;
public bool Contains(int value)
{
return value >= Start && value <= End;
}
public int[] ToArray()
{
int[] result = new int[Length];
for (int i = 0; i < Length; i++)
{
result[i] = Start + i;
}
return result;
}
}
// استفاده
Range range = new Range(1, 10);
Console.WriteLine($"Length: {range.Length}"); // 10
Console.WriteLine($"Contains 5: {range.Contains(5)}"); // True
Console.WriteLine($"Contains 15: {range.Contains(15)}"); // False
int[] numbers = range.ToArray();
Console.WriteLine(string.Join(", ", numbers)); // 1,2,3,4,5,6,7,8,9,10
---
⏱️ قسمت 8: Struct در مقابل Class – کدام را استفاده کنیم؟
از Struct استفاده کنید وقتی:
· دادهها کوچک هستند (کمتر از 16 بایت)
· نیاز به کپی کردن مکرر دارید
· نیازی به ارثبری ندارید
· نوع داده ساده و مستقل است (مثل نقطه، رنگ، محدوده)
از Class استفاده کنید وقتی:
· دادهها بزرگ هستند
· نیاز به ارثبری دارید
· نیاز به رفتارهای پیچیده دارید
· شیء باید قابلیت تغییر (Mutable) داشته باشد
csharp
// خوب برای Struct (داده کوچک)
struct Coordinate
{
public double Latitude;
public double Longitude;
}
struct Size
{
public int Width;
public int Height;
}
// خوب برای Class (داده بزرگ و رفتار پیچیده)
class Customer
{
public string Name { get; set; }
public string Email { get; set; }
public List<Order> Orders { get; set; }
}
---
✅ تمرین نهایی درس دوازدهم
برنامهای بنویسید که:
1. Enum ای برای OrderStatus (Pending, Processing, Shipped, Delivered, Cancelled)
2. Struct ای برای Product (Name, Price, Quantity)
3. Struct ای برای Order (Id, CustomerName, List<Product>, Status)
4. امکانات: افزودن محصول، نمایش سفارش، تغییر وضعیت
csharp
using System;
using System.Collections.Generic;
enum OrderStatus
{
Pending,
Processing,
Shipped,
Delivered,
Cancelled
}
struct Product
{
public string Name;
public double Price;
public int Quantity;
public Product(string name, double price, int quantity)
{
Name = name;
Price = price;
Quantity = quantity;
}
public double TotalPrice => Price * Quantity;
public void Display()
{
Console.WriteLine($" - {Name}: {Quantity} x {Price:C} = {TotalPrice:C}");
}
}
struct Order
{
public int Id;
public string CustomerName;
public List<Product> Products;
public OrderStatus Status;
public Order(int id, string customerName)
{
Id = id;
CustomerName = customerName;
Products = new List<Product>();
Status = OrderStatus.Pending;
}
public void AddProduct(Product product)
{
Products.Add(product);
Console.WriteLine($"Added {product.Quantity}x {product.Name} to order #{Id}");
}
public double GetTotal()
{
double total = 0;
foreach (Product p in Products)
{
total += p.TotalPrice;
}
return total;
}
public void ChangeStatus(OrderStatus newStatus)
{
Status = newStatus;
Console.WriteLine($"Order #{Id} status changed to {Status}");
}
public void Display()
{
Console.WriteLine($"\n=== Order #{Id} ===");
Console.WriteLine($"Customer: {CustomerName}");
Console.WriteLine($"Status: {Status}");
Console.WriteLine("Products:");
if (Products.Count == 0)
{
Console.WriteLine(" (empty)");
}
else
{
foreach (Product p in Products)
{
p.Display();
}
}
Console.WriteLine($"Total: {GetTotal():C}");
Console.WriteLine("=================");
}
}
class Program
{
static void Main()
{
// ساخت سفارش
Order order1 = new Order(1001, "Ali Mohammadi");
Order order2 = new Order(1002, "Sara Ahmadi");
// افزودن محصولات
Console.WriteLine("=== Adding Products ===");
order1.AddProduct(new Product("Laptop", 15000000, 1));
order1.AddProduct(new Product("Mouse", 250000, 2));
order2.AddProduct(new Product("Keyboard", 850000, 1));
order2.AddProduct(new Product("Monitor", 5500000, 1));
order2.AddProduct(new Product("Headphones", 1200000, 1));
// نمایش سفارشها
order1.Display();
order2.Display();
// تغییر وضعیت
Console.WriteLine("\n=== Status Updates ===");
order1.ChangeStatus(OrderStatus.Processing);
order1.ChangeStatus(OrderStatus.Shipped);
order2.ChangeStatus(OrderStatus.Delivered);
// نمایش نهایی
order1.Display();
order2.Display();
Console.WriteLine("\nPress Enter to exit...");
Console.ReadLine();
}
}
`--- 📌 جمعبندی درس دوازدهم مفهوم کاربرد مثال Enum مجموعه ثابتهای نامدار Days.Monday Struct نوع مقدار برای دادههای کوچک Point p = new Point(10, 20) Class نوع مرجع برای دادههای بزرگ Customer c = new Customer() نکات کلیدی Enum: · مقادیر از 0 شروع میشوند (قابل تغییر) · میتوان به عدد و متن تبدیل کرد · قابلیت خواندن کد را بالا میبرد نکات کلیدی Struct: · نوع مقدار (Value Type) است · روی Stack ذخیره میشود · سریعتر از Class برای دادههای کوچک · نمیتوان از آن ارث برد · مقایسه بر اساس مقادیر است نه مرجع --- 🧪 تمرین برای شما 1. Enum ای برای Month (12 ماه) بسازید و برنامهای بنویسید که تعداد روزهای هر ماه را چاپ کند 2. Struct ای برای Time (Hour, Minute, Second) بسازید با متد ToSeconds() و ToString() 3. Struct ای برای Fraction (صورت و مخرج) بسازید با متدهای جمع، تفریق، ضرب و تقسیم 4. تفاوت عملی Struct و Class را با یک مثال نشان دهید (نشان دهید کپی شدن چطور کار میکند) --- اگر این درس را کامل فهمیدید، بگویید تا درس سیزدهم (Delegates و Events) را شروع کنیم. سوالی بود بپرسید.
خیلی خوب، رسیدیم به درس سیزدهم: Delegates (نمایندهها) و Events (رویدادها).
این درس کمی پیشرفتهتر است اما خیلی کاربردی. Delegates به شما اجازه میدهند متدها را به عنوان متغیر استفاده کنید.
یک پروژه جدید بسازید (dotnet new console) و کدها را همراه من بنویسید و اجرا کنید.
---
📘 درس سیزدهم – Delegates و Events
🎯 سرفصلها:
1. Delegate چیست؟
2. تعریف و استفاده از Delegate
3. Multicast Delegate (چند متدی)
4. Func، Action، Predicate (Delegateهای آماده)
5. Event چیست؟
6. تفاوت Event با Delegate
7. مثال واقعی (دکمه کلیک)
8. تمرین جامع
---
⏱️ قسمت 1: Delegate چیست؟
Delegate = یک متغیر که میتواند به یک متد اشاره کند (اشارهگر به متد)
csharp
// 1. تعریف Delegate (امضای متد را مشخص میکند)
delegate int MathOperation(int a, int b);
// 2. متدهایی با همان امضا
int Add(int x, int y)
{
return x + y;
}
int Multiply(int x, int y)
{
return x * y;
}
// 3. استفاده
MathOperation operation = Add; // اشاره به متد Add
int result1 = operation(5, 3); // 8
Console.WriteLine($"Add: {result1}");
operation = Multiply; // تغییر اشاره به متد Multiply
int result2 = operation(5, 3); // 15
Console.WriteLine($"Multiply: {result2}");
📌 Delegate مانند یک قالب است:
· امضای متد را مشخص میکند (نوع ورودی و خروجی)
· هر متدی با همین امضا را میتوان به آن اختصاص داد
---
⏱️ قسمت 2: کاربرد واقعی Delegate
csharp
delegate bool FilterFunction(int number);
// متدهای فیلتر
bool IsEven(int n) => n % 2 == 0;
bool IsGreaterThanTen(int n) => n > 10;
bool IsPrime(int n)
{
if (n < 2) return false;
for (int i = 2; i <= Math.Sqrt(n); i++)
if (n % i == 0) return false;
return true;
}
// متدی که از Delegate استفاده میکند
int[] FilterNumbers(int[] numbers, FilterFunction filter)
{
List<int> result = new List<int>();
foreach (int n in numbers)
{
if (filter(n))
result.Add(n);
}
return result.ToArray();
}
// استفاده
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
int[] evens = FilterNumbers(nums, IsEven);
int[] greaterThanTen = FilterNumbers(nums, IsGreaterThanTen);
int[] primes = FilterNumbers(nums, IsPrime);
Console.WriteLine($"Evens: {string.Join(", ", evens)}");
Console.WriteLine($"Greater than 10: {string.Join(", ", greaterThanTen)}");
Console.WriteLine($"Primes: {string.Join(", ", primes)}");
---
⏱️ قسمت 3: Multicast Delegate (چند متدی)
یک Delegate میتواند به چندین متد اشاره کند.
csharp
delegate void PrintDelegate(string message);
void PrintToConsole(string msg)
{
Console.WriteLine($"Console: {msg}");
}
void PrintToFile(string msg)
{
Console.WriteLine($"File: [LOG] {msg}");
}
void PrintToDatabase(string msg)
{
Console.WriteLine($"Database: storing '{msg}'");
}
// استفاده از Multicast
PrintDelegate printer = PrintToConsole;
printer += PrintToFile; // اضافه کردن متد دوم
printer += PrintToDatabase; // اضافه کردن متد سوم
printer("Hello World!"); // هر سه متد اجرا میشوند
// حذف یک متد
printer -= PrintToFile;
Console.WriteLine("\nAfter removing PrintToFile:");
printer("Another message");
خروجی:
Console: Hello World!
File: [LOG] Hello World!
Database: storing 'Hello World!'
After removing PrintToFile:
Console: Another message
Database: storing 'Another message'
---
⏱️ قسمت 4: Delegateهای آماده (Func, Action, Predicate)
به جای تعریف Delegate خودمان، میتوانیم از اینها استفاده کنیم:
نوع ورودی خروجی کاربرد
Action 0 تا 16 پارامتر void بدون خروجی
Func 0 تا 16 پارامتر یک مقدار با خروجی
Predicate 1 پارامتر bool شرط
Action (بدون خروجی):
csharp
// Action بدون پارامتر
Action sayHello = () => Console.WriteLine("Hello!");
sayHello();
// Action با یک پارامتر
Action<string> greet = (name) => Console.WriteLine($"Hello {name}!");
greet("Ali");
// Action با دو پارامتر
Action<string, int> introduce = (name, age) =>
Console.WriteLine($"I'm {name}, {age} years old");
introduce("Sara", 25);
Func (با خروجی):
`csharp // Func با یک ورودی و یک خروجی Func<int, int> square = (x) => x * x; Console.WriteLine(square(5)); // 25
// Func با دو ورودی و یک خروجی
Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(10, 20)); // 30
// Func با string ورودی و bool خروجی
Func<string, bool> isEmpty = (s) => string.IsNullOrEmpty(s);
Console.WriteLine(isEmpty("")); // True
Console.WriteLine(isEmpty("Hi")); // False
Predicate (شرط):
csharp
// Predicate = Func<T, bool>
Predicate<int> isEven = (n) => n % 2 == 0;
Console.WriteLine(isEven(4)); // True
Console.WriteLine(isEven(5)); // False
// استفاده در List
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> evens = numbers.FindAll(isEven);
Console.WriteLine($"Evens: {string.Join(", ", evens)}");
---
⏱️ قسمت 5: Event چیست؟
Event = یک Delegate خاص که فقط در کلاس خودش صدا زده میشود.
csharp
class Button
{
// تعریف Delegate
public delegate void ClickHandler(object sender, EventArgs e);
// تعریف Event
public event ClickHandler Click;
// متد برای صدا زدن Event
public void OnClick()
{
Console.WriteLine("Button was clicked!");
Click?.Invoke(this, EventArgs.Empty); // اگر کسی مشترک شده باشد، صدا بزن
}
}
class Program
{
static void Main()
{
Button btn = new Button();
// اشتراک در رویداد
btn.Click += Button_Click;
btn.Click += Button_Click2;
// شبیهسازی کلیک
btn.OnClick();
}
static void Button_Click(object sender, EventArgs e)
{
Console.WriteLine("Event handler 1 executed");
}
static void Button_Click2(object sender, EventArgs e)
{
Console.WriteLine("Event handler 2 executed");
}
}
---
⏱️ قسمت 6: تفاوت Event با Delegate
ویژگی Delegate Event
قابل صدا زدن از بیرون ✅ ❌ (فقط داخل کلاس)
قابل اشتراک از بیرون ✅ ✅ (با +=)
قابل لغو اشتراک از بیرون ✅ ✅ (با -=)
قابل مقداردهی از بیرون ✅ (=) ❌ (فقط += و -=)
csharp
class Test
{
public delegate void MyDelegate(string msg);
public MyDelegate Del; // Delegate معمولی
public event MyDelegate Evt; // Event
public void TestMethod()
{
Del("From inside"); // ✅
Evt("From inside"); // ✅
}
}
// در بیرون
Test t = new Test();
t.Del = (msg) => Console.WriteLine(msg); // ✅
// t.Evt = (msg) => Console.WriteLine(msg); // ❌ خطا - نمیتوان =
t.Del += (msg) => Console.WriteLine(msg); // ✅
t.Evt += (msg) => Console.WriteLine(msg); // ✅
// t.Del("From outside"); // ✅
// t.Evt("From outside"); // ❌ خطا - نمیتوان از بیرون صدا زد
---
⏱️ قسمت 7: مثال واقعی – سیستم آب و هوا
csharp
using System;
using System.Collections.Generic;
// کلاس اطلاعات آب و هوا
class WeatherData
{
public double Temperature { get; set; }
public double Humidity { get; set; }
public string Condition { get; set; }
public override string ToString()
{
return $"{Condition}, {Temperature}°C, {Humidity}% humidity";
}
}
// کلاس ایستگاه آب و هوا (منتشرکننده رویداد)
class WeatherStation
{
// تعریف Delegate و Event
public delegate void WeatherUpdateHandler(object sender, WeatherData data);
public event WeatherUpdateHandler WeatherUpdated;
private WeatherData currentData;
public WeatherStation()
{
currentData = new WeatherData { Temperature = 25, Humidity = 60, Condition = "Sunny" };
}
public void UpdateWeather(double temp, double humidity, string condition)
{
currentData.Temperature = temp;
currentData.Humidity = humidity;
currentData.Condition = condition;
Console.WriteLine($"\n[WeatherStation] Weather updated: {currentData}");
// اطلاع به مشترکین
WeatherUpdated?.Invoke(this, currentData);
}
}
// کلاس نمایشگر (مشترک رویداد)
class DisplayScreen
{
private string name;
public DisplayScreen(string screenName)
{
name = screenName;
}
public void OnWeatherUpdated(object sender, WeatherData data)
{
Console.WriteLine($"[{name}] Displaying: {data}");
}
}
// کلاس هشداردهنده (مشترک دیگر)
class AlertSystem
{
public void OnWeatherUpdated(object sender, WeatherData data)
{
if (data.Temperature > 35)
Console.WriteLine($"[Alert] HEAT WARNING! {data.Temperature}°C");
else if (data.Temperature < 0)
Console.WriteLine($"[Alert] FREEZE WARNING! {data.Temperature}°C");
else if (data.Humidity > 80)
Console.WriteLine($"[Alert] HIGH HUMIDITY! {data.Humidity}%");
}
}
// برنامه اصلی
class Program
{
static void Main()
{
WeatherStation station = new WeatherStation();
DisplayScreen screen1 = new DisplayScreen("Living Room");
DisplayScreen screen2 = new DisplayScreen("Phone App");
AlertSystem alerts = new AlertSystem();
// اشتراک در رویداد
station.WeatherUpdated += screen1.OnWeatherUpdated;
station.WeatherUpdated += screen2.OnWeatherUpdated;
station.WeatherUpdated += alerts.OnWeatherUpdated;
// بهروزرسانی آب و هوا
station.UpdateWeather(28, 55, "Sunny");
station.UpdateWeather(38, 45, "Hot");
station.UpdateWeather(-2, 70, "Snowy");
station.UpdateWeather(30, 85, "Rainy");
Console.WriteLine("\nPress Enter to exit...");
Console.ReadLine();
}
}
---
✅ تمرین نهایی درس سیزدهم
برنامهای بنویسید که:
1. کلاس BankAccount با رویداد BalanceChanged
2. وقتی موجودی تغییر کرد، چندین مشترک مطلع شوند
3. از Action و Func در متدهای مختلف استفاده کنید
csharp
using System;
class BankAccount
{
private double balance;
// تعریف رویداد
public event Action<object, double, double> BalanceChanged; // sender, oldBalance, newBalance
public string AccountNumber { get; set; }
public string Owner { get; set; }
public double Balance
{
get { return balance; }
private set
{
double oldBalance = balance;
balance = value;
// صدا زدن رویداد
BalanceChanged?.Invoke(this, oldBalance, balance);
}
}
public BankAccount(string number, string owner, double initialBalance)
{
AccountNumber = number;
Owner = owner;
balance = initialBalance;
}
public void Deposit(double amount)
{
if (amount > 0)
{
Balance += amount;
Console.WriteLine($"Deposited: {amount:C}");
}
}
public void Withdraw(double amount)
{
if (amount > 0 && amount <= Balance)
{
Balance -= amount;
Console.WriteLine($"Withdrawn: {amount:C}");
}
else
{
Console.WriteLine("Insufficient balance or invalid amount!");
}
}
}
class Program
{
static void Main()
{
BankAccount account = new BankAccount("123456789", "Ali Rezaei", 1000000);
// مشترکین رویداد
account.BalanceChanged += OnBalanceChanged_Logger;
account.BalanceChanged += OnBalanceChanged_Email;
account.BalanceChanged += OnBalanceChanged_SMS;
// انجام عملیات
Console.WriteLine("=== Bank Account Transactions ===\n");
account.Deposit(500000);
account.Withdraw(200000);
account.Withdraw(1500000); // ناموفق
account.Deposit(1000000);
Console.WriteLine("\nPress Enter to exit...");
Console.ReadLine();
}
static void OnBalanceChanged_Logger(object sender, double oldBalance, double newBalance)
{
BankAccount acc = (BankAccount)sender;
Console.WriteLine($"[LOG] Account {acc.AccountNumber}: {oldBalance:C} → {newBalance:C}");
}
static void OnBalanceChanged_Email(object sender, double oldBalance, double newBalance)
{
BankAccount acc = (BankAccount)sender;
Console.WriteLine($"[EMAIL] Dear {acc.Owner}, your balance changed to {newBalance:C}");
}
static void OnBalanceChanged_SMS(object sender, double oldBalance, double newBalance)
{
Console.WriteLine($"[SMS] Balance update: {newBalance:C}");
}
}
`--- 📌 جمعبندی درس سیزدهم مفهوم توضیح مثال delegate تعریف نماینده delegate int MyDel(int x); Action Delegate بدون خروجی Action<string> print = s => Console.WriteLine(s); Func Delegate با خروجی Func<int,int> square = x => x*x; Predicate Delegate شرط Predicate<int> isEven = n => n%2==0; event رویداد (نسخه امن Delegate) public event Action MyEvent; کاربردهای اصلی: · Callback (فراخوانی بعد از انجام کار) · Event Handling (مدیریت رویدادها مانند کلیک) · LINQ (بسیاری از متدهای LINQ از Delegate استفاده میکنند) · ساختارهای انعطافپذیر --- 🧪 تمرین برای شما 1. یک Func بنویسید که دو string بگیرد و برگرداند طول بزرگترین آنها 2. یک Action بنویسید که یک آرایه بگیرد و همه اعضا را چاپ کند 3. یک کلاس Timer بسازید با رویداد Tick که هر ثانیه یک بار صدا زده شود 4. یک برنامه سفارش آنلاین بسازید که رویدادهای OrderPlaced، OrderShipped، OrderDelivered داشته باشد --- اگر این درس را کامل فهمیدید، بگویید تا درس چهاردهم (LINQ) را شروع کنیم. سوالی بود بپرسید.
خیلی خوب، پس شروع میکنیم درس چهاردهم – LINQ قسمت اول: آشنایی با LINQ و متدهای پایه.
یک پروژه جدید کنسولی بسازید (dotnet new console) و کدها را همراه من بنویسید و اجرا کنید.
---
📘 درس چهاردهم – LINQ قسمت 1: آشنایی با LINQ
🎯 سرفصلها:
1. LINQ چیست و چرا نیاز داریم؟
2. دو روش نوشتن LINQ (Query Syntax و Method Syntax)
3. متد Where (فیلتر کردن)
4. متد Select (انتخاب و تبدیل)
5. متدهای First، FirstOrDefault، Single، SingleOrDefault
6. متد ToList و اجرای دیررس (Deferred Execution)
7. تمرین جامع
---
⏱️ قسمت 1: LINQ چیست؟
LINQ = Language Integrated Query
زبانی برای پرس و جو از دادهها درون خود سیشارپ.
بدون LINQ (کد قدیمی و طولانی):
csharp
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> evens = new List<int>();
foreach (int n in numbers)
{
if (n % 2 == 0)
{
evens.Add(n);
}
}
با LINQ (کد کوتاه و خواناتر):
csharp
using System.Linq; // اضافه کردن این using لازم است
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var evens = numbers.Where(n => n % 2 == 0).ToList();
📌 نکته: حتماً using System.Linq; را در بالای فایل اضافه کنید.
---
⏱️ قسمت 2: دو روش نوشتن LINQ
روش اول: Method Syntax (روش متدی) – رایجتر
csharp
var result = numbers.Where(n => n > 5).Select(n => n * 2);
روش دوم: Query Syntax (روش شبه SQL) – شبیه به SQL
csharp
var result = from n in numbers
where n > 5
select n * 2;
مقایسه هر دو روش:
csharp
int[] scores = { 85, 92, 78, 90, 88, 70, 95 };
// Method Syntax
var highScores1 = scores.Where(s => s >= 90).OrderBy(s => s);
// Query Syntax
var highScores2 = from s in scores
where s >= 90
orderby s
select s;
Console.WriteLine("High scores (>=90):");
foreach (var score in highScores1)
{
Console.Write(score + " "); // 90 92 95
}
📌 نکته: هر دو روش نتیجه یکسان دارند. Method Syntax پرکاربردتر است.
---
⏱️ قسمت 3: متد Where (فیلتر کردن)
Where برای فیلتر کردن دادهها بر اساس یک شرط استفاده میشود.
csharp
List<string> names = new List<string>
{
"Ali", "Reza", "Sara", "Mohammad", "Neda", "Hossein"
};
// نامهایی که با "A" شروع میشوند
var startsWithA = names.Where(n => n.StartsWith("A"));
Console.WriteLine("Starts with A: " + string.Join(", ", startsWithA));
// نامهایی که طول آنها بیشتر از 4 است
var longNames = names.Where(n => n.Length > 4);
Console.WriteLine("Long names: " + string.Join(", ", longNames));
// ترکیب چند شرط
var result = names.Where(n => n.Length > 3 && n.Contains("e"));
Console.WriteLine("Long names with 'e': " + string.Join(", ", result));
---
⏱️ قسمت 4: متد Select (انتخاب و تبدیل)
Select برای تبدیل هر عنصر به شکل دیگری استفاده میشود.
csharp
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
// تبدیل هر عدد به مربع آن
var squares = numbers.Select(n => n * n);
Console.WriteLine("Squares: " + string.Join(", ", squares)); // 1,4,9,16,25
// تبدیل هر عدد به متن
var textNumbers = numbers.Select(n => $"Number: {n}");
foreach (var item in textNumbers)
{
Console.WriteLine(item);
}
مثال با کلاس Person:
csharp
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string City { get; set; }
}
List<Person> people = new List<Person>
{
new Person { Name = "Ali", Age = 25, City = "Tehran" },
new Person { Name = "Sara", Age = 30, City = "Shiraz" },
new Person { Name = "Reza", Age = 22, City = "Tehran" },
new Person { Name = "Neda", Age = 28, City = "Isfahan" }
};
// فقط نامها را انتخاب کن
var namesOnly = people.Select(p => p.Name);
Console.WriteLine("Names: " + string.Join(", ", namesOnly));
// نام و سن را به صورت یک شیء ناشناس (Anonymous) انتخاب کن
var nameAndAge = people.Select(p => new { p.Name, p.Age });
foreach (var item in nameAndAge)
{
Console.WriteLine($"{item.Name} is {item.Age} years old");
}
---
⏱️ قسمت 5: ترکیب Where و Select
`csharp List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// اعداد زوج را گرفته و آنها را ۲ برابر کن
var result = numbers
.Where(n => n % 2 == 0) // 2,4,6,8,10
.Select(n => n * 2); // 4,8,12,16,20
Console.WriteLine("Even numbers doubled: " + string.Join(", ", result));
// با Query Syntax
var result2 = from n in numbers
where n % 2 == 0
select n * 2;
---
⏱️ قسمت 6: متدهای First، FirstOrDefault، Single
متد توضیح
First() اولین عنصر را برمیگرداند (اگر نباشد خطا میدهد)
FirstOrDefault() اولین عنصر را برمیگرداند (اگر نباشد null میدهد)
Single() فقط یک عنصر باید باشد (اگر بیشتر یا کمتر باشد خطا)
SingleOrDefault() فقط یک عنصر باید باشد (اگر کمتر باشد null)
csharp
List<int> numbers = new List<int> { 10, 20, 30, 40, 50 };
int first = numbers.First();
Console.WriteLine($"First: {first}"); // 10
int firstGreaterThan25 = numbers.First(n => n > 25);
Console.WriteLine($"First > 25: {firstGreaterThan25}"); // 30
int firstOrDefault = numbers.FirstOrDefault(n => n > 100);
Console.WriteLine($"First > 100: {firstOrDefault}"); // 0 (default)
List<int> emptyList = new List<int>();
int safeResult = emptyList.FirstOrDefault();
Console.WriteLine($"FirstOrDefault on empty: {safeResult}"); // 0
مثال با اشیاء:
csharp
List<Person> people = new List<Person>
{
new Person { Name = "Ali", Age = 25, City = "Tehran" },
new Person { Name = "Sara", Age = 30, City = "Shiraz" }
};
// پیدا کردن شخص با نام خاص
Person? person = people.FirstOrDefault(p => p.Name == "Ali");
if (person != null)
{
Console.WriteLine($"Found: {person.Name}, {person.Age}");
}
// Single - اگر بیش از یک عنصر باشد خطا میدهد
try
{
Person single = people.Single(p => p.City == "Tehran"); // فقط یک نفر از تهران
Console.WriteLine($"Single from Tehran: {single.Name}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
---
⏱️ قسمت 7: متد ToList و اجرای دیررس
نکته مهم: اکثر متدهای LINQ اجرای دیررس (Deferred Execution) دارند. یعنی تا زمانی که به نتیجه نیاز نباشد، اجرا نمیشوند.
csharp
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
// اینجا هنوز اجرا نشده
var query = numbers.Where(n => n > 2);
// حالا که با ToList تبدیل میکنیم، اجرا میشود
var result1 = query.ToList();
// یا وقتی در حلقه استفاده میکنیم، اجرا میشود
foreach (var n in query) // اینجا اجرا میشود
{
Console.WriteLine(n);
}
تفاوت اجرای دیررس و فوری:
csharp
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
// اجرای دیررس (Deferred)
var deferred = numbers.Where(n => n > 2);
// اجرای فوری (Immediate)
var immediate = numbers.Where(n => n > 2).ToList();
// حالا عدد جدید اضافه میکنیم
numbers.Add(10);
// deferred دوباره اجرا میشود و عدد 10 را هم میبیند
Console.WriteLine("Deferred: " + string.Join(", ", deferred)); // 3,4,5,10
// immediate قبلاً اجرا شده و تغییر نمیکند
Console.WriteLine("Immediate: " + string.Join(", ", immediate)); // 3,4,5
---
✅ تمرین نهایی درس چهاردهم
برنامهای بنویسید که:
1. لیستی از محصولات (Product) با Name، Price، Category بسازد
2. محصولات گرانتر از 100,000 تومان را پیدا کند
3. فقط نام محصولات را نمایش دهد
4. اولین محصول از دسته "Electronics" را پیدا کند
5. مجموع قیمت همه محصولات را محاسبه کند
csharp
using System;
using System.Collections.Generic;
using System.Linq;
class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
class Program
{
static void Main()
{
List<Product> products = new List<Product>
{
new Product { Name = "Laptop", Price = 15000000, Category = "Electronics" },
new Product { Name = "Mouse", Price = 250000, Category = "Electronics" },
new Product { Name = "Book", Price = 85000, Category = "Books" },
new Product { Name = "Pen", Price = 15000, Category = "Stationery" },
new Product { Name = "Keyboard", Price = 850000, Category = "Electronics" },
new Product { Name = "Notebook", Price = 45000, Category = "Stationery" },
new Product { Name = "Phone", Price = 12000000, Category = "Electronics" }
};
Console.WriteLine("=== Product List ===");
foreach (var p in products)
{
Console.WriteLine($"{p.Name}: {p.Price:C} ({p.Category})");
}
// 1. محصولات گرانتر از 100,000 تومان
var expensive = products.Where(p => p.Price > 100000);
Console.WriteLine("\n=== Products > 100,000 ===");
foreach (var p in expensive)
{
Console.WriteLine($"{p.Name}: {p.Price:C}");
}
// 2. فقط نام محصولات گرانقیمت
var expensiveNames = products
.Where(p => p.Price > 100000)
.Select(p => p.Name);
Console.WriteLine("\n=== Names of expensive products ===");
Console.WriteLine(string.Join(", ", expensiveNames));
// 3. اولین محصول از دسته Electronics
var firstElectronic = products.FirstOrDefault(p => p.Category == "Electronics");
if (firstElectronic != null)
{
Console.WriteLine($"\n=== First Electronic Product ===");
Console.WriteLine($"{firstElectronic.Name} - {firstElectronic.Price:C}");
}
// 4. مجموع قیمت همه محصولات
decimal totalPrice = products.Sum(p => p.Price);
Console.WriteLine($"\n=== Total Inventory Value ===");
Console.WriteLine($"{totalPrice:C}");
// 5. محصولات الکترونیک با قیمت کمتر از 1,000,000
var budgetElectronics = products
.Where(p => p.Category == "Electronics" && p.Price < 1000000)
.Select(p => p.Name);
Console.WriteLine("\n=== Budget Electronics (< 1,000,000) ===");
Console.WriteLine(string.Join(", ", budgetElectronics));
Console.WriteLine("\nPress Enter to exit...");
Console.ReadLine();
}
}
`--- 📌 جمعبندی درس چهاردهم متد کاربرد مثال Where فیلتر کردن .Where(x => x > 5) Select تبدیل کردن .Select(x => x * 2) First اولین عنصر .First() FirstOrDefault اولین عنصر (امن) .FirstOrDefault() Single فقط یک عنصر .Single(x => x.Id == 5) ToList تبدیل به List .ToList() نکات کلیدی: · حتماً using System.Linq; را اضافه کنید · متدهای LINQ اکثراً اجرای دیررس دارند · Method Syntax رایجتر از Query Syntax است --- 🧪 تمرین برای شما 1. لیستی از اعداد بسازید و اعداد بخشپذیر بر 3 را پیدا کنید 2. لیستی از رشتهها بسازید و رشتههایی که طول آنها بیشتر از 5 است را با حروف بزرگ نمایش دهید 3. با کلاس Student (Name, Score, Grade) لیستی بسازید و دانشجویانی که نمره بالای 17 دارند را پیدا کنید --- اگر این درس را کامل فهمیدید، بگویید تا قسمت دوم LINQ (مرتبسازی و گروهبندی) را شروع کنیم. سوالی بود بپرسید.