Introduction to Reflection

ู…ูˆุถูˆุน ุงู„ู†ู‡ุงุฑุฏุฉ ุดูŠู‚ ูˆู…ู…ุชุน ุฌุฏู‹ุงุŒ ู‡ูˆ ู…ุชู‚ุฏู… ุดูˆูŠุฉ ุจุณ ู‡ู†ุจุณุทู‡ ู…ุน ุจุนุถ. ู„ู…ุง ุชูู‡ู…ู‡ ูƒูˆูŠุณุŒ ู‡ุชุชุญู…ุณ ุฌุฏู‹ุง ูˆู‡ุชุญุงูˆู„ ุชู„ุงู‚ูŠ ุฃููƒุงุฑ ุชุณุชุนู…ู„ู‡ ููŠู‡ุงุŒ ู„ุฅู† ุงู„ู…ูˆุถูˆุน ุฏู‡ powerful ุฌุฏู‹ุง ูˆุจูŠุฏูŠู„ูƒ ุฅู…ูƒุงู†ูŠุงุช ุฑู‡ูŠุจุฉ ูˆุงู†ุช ุจุชูƒุชุจ ูƒูˆุฏ ููŠ ุงู„ู€ .NET.

ู„ูˆ ุงู†ุช ุดุบุงู„ ุญุงู„ูŠู‹ุง ุนู„ู‰ ู…ุดุงุฑูŠุน ุญู‚ูŠู‚ูŠุฉุŒ ูุงู†ุช ุณูˆุงุก ุชุนุฑู ุฃูˆ ู…ุชุนุฑูุดุŒ ูุงู†ุช ุจุชุณุชุฎุฏู…ู‡ ุจุดูƒู„ ุฃูˆ ุจุขุฎุฑุŒ ุฃูˆ ุจุชุณุชุฎุฏู… library ู‡ูŠ ุงู„ู„ูŠ ุจุชุณุชุฎุฏู…ู‡ุŒ ู„ุฅู†ู‡ ุจู‚ู‰ ุฏุงุฎู„ ุชู‚ุฑูŠุจู‹ุง ููŠ ูƒู„ ุญุงุฌุฉ.

ู…ูˆุถูˆุนู†ุง ุงู„ู†ู‡ุงุฑุฏุฉ ุงุณู…ู‡ Reflection.

What is Reflection?

ูƒู„ู…ุฉ reflection ู…ุนู†ุงู‡ุง โ€œุงู†ุนูƒุงุณโ€. ู„ู…ุง ุจุชู‚ู ู‚ุฏุงู… ุงู„ู…ุฑุงูŠุฉ ุจุชุดูˆู ุงู†ุนูƒุงุณ ู„ูŠูƒุŒ ุจุชุดูˆู ูˆุดูƒ ูˆู…ู†ุงุฎูŠุฑูƒ ูˆูƒู„ ุชูุงุตูŠู„ูƒ.

ู†ูุณ ุงู„ูƒู„ุงู… ุจุงู„ู†ุณุจุฉ ู„ู„ูƒูˆุฏุŒ ุงู„ุงู†ุนูƒุงุณ ุจูŠู…ูƒู†ูƒ ุฅู†ูƒ ุชุดูˆู ูˆุชุทู„ุน ุนู„ู‰ ุงู„ุชูุงุตูŠู„ ุงู„ุฏุงุฎู„ูŠุฉ ู„ู„ู€ Assembly ู…ู† ุบูŠุฑ ู…ุง ูŠูƒูˆู† ู…ุนุงูƒ ุงู„ู€ source code ุจุชุงุนู‡ุŒ ุฃูˆ ุญุชู‰ ู„ูˆ ู…ุนุงูƒ ุงู„ู€ source code ุจุณ ุนุงูŠุฒ ุชุนู…ู„ ุงู„ูƒู„ุงู… ุฏู‡ ููŠ ุงู„ู€ run-time.

ู‡ุชูู‡ู… ุฃูƒุชุฑ ูˆุงุญู†ุง ู…ุงุดูŠูŠู†ุŒ ุจุณ ุฎู„ูŠู†ุง ุงู„ุฃูˆู„ ู†ุนุฑู ุฅูŠู‡ ู‡ูˆ ุงู„ู€ Assembly ู„ุฅู†ู‡ ู‡ูˆ ุฏู‡ ุงู„ู…ุฏุฎู„ ุงู„ุฑุฆูŠุณูŠ ู„ู„ู€ Reflection.

What is an Assembly?

ูƒู„ู…ุฉ assembly ููŠ ู„ุบุงุช ุงู„ุจุฑู…ุฌุฉ ุนู…ูˆู…ู‹ุงุŒ ูˆููŠ ุงู„ู€ .NET ุชุญุฏูŠุฏู‹ุงุŒ ุจู†ุชูƒู„ู… ุนู† ุงู„ู€ binary files ุงู„ู„ูŠ ุจุชุทู„ุน ู…ู† ุนู…ู„ูŠุฉ ุงู„ู€ build ู„ู„ูƒูˆุฏ ุจุชุงุนูƒ.

ู„ู…ุง ุจู†ุนู…ู„ build ู„ุจุฑูˆุฌูƒุช ุฌุฏูŠุฏุŒ ุจู†ู„ุงู‚ูŠ ููŠ ุงู„ู€ output folder ู…ู„ูุงุช ุงู„ุงู…ุชุฏุงุฏ ุจุชุงุนู‡ุง .dll ูˆ .exe. ูƒู„ ู…ู„ู ู…ู† ุฏูˆู„ ุจู†ู‚ูˆู„ ุนู„ูŠู‡ Assembly. ุจู…ุง ุฅู†ู†ุง ุดุบุงู„ูŠู† .NET CoreุŒ ุฎู„ูŠู†ุง ู†ุฑูƒุฒ ุฃูƒุชุฑ ุนู„ู‰ ุงู„ู€ DLL.

ูุงู„ู€ Assembly ููŠ .NET ู‡ูˆ ู…ู„ู ุงู„ู€ DLL ุงู„ู„ูŠ ุจูŠุฎุฑุฌ ู„ู…ุง ุชุนู…ู„ build ู„ู„ุจุฑูˆุฌูƒุช ุจุชุงุนูƒ.

ุงู„ู€ Assembly ุฏู‡ ุจูŠูƒูˆู† ุดุงูŠู„ ุญุงุฌุงุช ูƒุชูŠุฑุŒ ู…ู†ู‡ุง:

  • ุงู„ู€ Metadata: ุฏูŠ ู…ุนู„ูˆู…ุงุช ุนู† ุงู„ู€ Assembly ู†ูุณู‡ ูˆู…ุญุชูˆูŠุงุชู‡ุŒ ุฒูŠ ุงุณู… ุงู„ู€ AssemblyุŒ ุงู„ู€ version ุจุชุงุนู‡ุŒ ุงู„ู€ locationุŒ ูˆุชูุงุตูŠู„ ุชุงู†ูŠุฉ ูƒุชูŠุฑ.
  • ุงู„ู€ Intermediate Language (IL): ุงุชูƒู„ู…ู†ุง ุนู† ุงู„ู€ IL ู‚ุจู„ ูƒุฏู‡. ุฏู‡ ุงู„ู„ุบุฉ ุงู„ูˆุณูŠุทุฉ ุงู„ู„ูŠ ุงู„ูƒูˆุฏ ุจุชุงุนูƒ ุจูŠุชุฑุฌู… ู„ูŠู‡ุง ูˆู‚ุช ุงู„ู€ compilation. ุงู„ูƒูˆุฏ ู…ุด ุจูŠุชุญูˆู„ ู„ู€ machine language ู…ุจุงุดุฑุฉุŒ ู„ุฃุŒ ุจูŠุชุญูˆู„ ุงู„ุฃูˆู„ ู„ู€ ILุŒ ูˆุจุนุฏ ูƒุฏู‡ ููŠ ุงู„ู€ run-time ุงู„ู€ IL ุจูŠุชุญูˆู„ ู„ู€ machine code.
  • ุงู„ู€ Embedded Resources: ุฏูŠ ู…ู„ูุงุช ุงู†ุช ุจุชุฏู…ุฌู‡ุง ู…ุน ุงู„ู€ Assembly ุจุชุงุนูƒ ู„ูˆ ุญุจูŠุช.

ุชุนุงู„ูˆุง ู†ุดูˆู ุงู„ูƒู„ุงู… ุฏู‡ ุจูŠุชู… ุฅุฒุงูŠ ุจุงู„ุชูุตูŠู„.

Getting Started with Reflection

ุนุดุงู† ู†ุจุฏุฃ ู†ุชุนุงู…ู„ ู…ุน ุงู„ู€ ReflectionุŒ ุฃูˆู„ ุญุงุฌุฉ ุจู†ุนู…ู„ู‡ุง ู‡ูŠ import ู„ู„ู€ namespace ุงู„ู„ูŠ ุงุณู…ู‡ System.Reflection.

using System.Reflection;

ุฏู‡ ุงู„ู„ูŠ ููŠู‡ ูƒู„ ุงู„ุฃุฏูˆุงุช ุงู„ู„ูŠ ู‡ู†ุญุชุงุฌู‡ุง. ุจุนุฏ ูƒุฏู‡ุŒ ุฃู†ุง ุนุงูŠุฒ ุฃูˆุตู„ ุฃูˆ ุขุฎุฏ reference ู„ู„ู€ Assembly.

ุงุญู†ุง ุงุชูู‚ู†ุง ุฅู† ุงู„ู€ Assembly ู‡ูˆ ู…ู„ู ุงู„ู€ DLL. ู„ู…ุง ุจุนู…ู„ run ู„ู„ุจุฑูˆุฌูƒุช ุจุชุงุนูŠุŒ ุนู…ู„ูŠุฉ ุงู„ู€ run ุจุชุนู…ู„ build ุงู„ุฃูˆู„ุŒ ูˆุงู„ู€ compiler ุจูŠุทู„ุน ุงู„ู€ AssemblyุŒ ูˆุจุนุฏูŠู† ุงู„ู€ debugger ุจูŠุงุฎุฏ ุงู„ู€ Assembly ุฏู‡ ูˆูŠุนู…ู„ู‡ attach ุนุดุงู† ุชู‚ุฏุฑ ุชุนู…ู„ debug.

ูุงู„ุจุฑูˆุฌูƒุช ุจุชุงุนูŠ ุงู„ู„ูŠ ู‡ูˆ CsharpAdvancedReflection ู„ู…ุง ุฃุนู…ู„ู‡ run ูˆู‚ุช ุชุดุบูŠู„ู‡ ุจู‚ู‰ ุงุณู…ู‡ Assembly.

ุนุดุงู† ุฃูˆุตู„ ู„ู‡ุŒ ููŠู‡ class ุงุณู…ู‡ Assembly ุฌูˆุงู‡ ุดูˆูŠุฉ methods ุฒูŠ:

  • GetEntryAssembly()
  • GetExecutingAssembly()
  • GetCallingAssembly()

ุฎู„ูŠู†ุง ุฏู„ูˆู‚ุชูŠ ููŠ GetExecutingAssembly(). ุงู„ู€ method ุฏูŠ ุจุชุฑุฌุนู„ูƒ reference ู„ู„ู€ Assembly ุงู„ู„ูŠ ููŠู‡ ุงู„ูƒูˆุฏ ุงู„ู„ูŠ ุจูŠุชู†ูุฐ ุญุงู„ูŠู‹ุง. ูŠุนู†ูŠ ุงู„ุณุทุฑ ุงู„ู„ูŠ ุจุชู†ุงุฏูŠ ููŠู‡ ุงู„ู€ method ุฏูŠุŒ ู‡ูŠุฑุฌุนู„ูƒ ุงู„ู€ Assembly ุจุชุงุน ุงู„ุจุฑูˆุฌูƒุช ุงู„ู„ูŠ ุงู„ุณุทุฑ ุฏู‡ ู…ูƒุชูˆุจ ููŠู‡.

// Get a reference to the currently executing assembly
Assembly assembly = Assembly.GetExecutingAssembly();

ุชุนุงู„ูˆุง ู†ุดูˆู ุฅูŠู‡ ุงู„ุชูุงุตูŠู„ ุงู„ู„ูŠ ู…ู…ูƒู† ู†ุนุฑูู‡ุง ุนู† ุงู„ู€ Assembly.

// Print the full name of the assembly
Console.WriteLine($"Assembly Name: {assembly.FullName}");
 
// Print the location (path) of the assembly file
Console.WriteLine($"Assembly Location: {assembly.Location}");

ู„ู…ุง ู†ุดุบู„ ุงู„ูƒูˆุฏ ุฏู‡ ู‡ู†ุดูˆู ุงู„ู†ุชูŠุฌุฉ:

Assembly Name: CsharpAdvancedReflection, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Assembly Location: C:\...\CsharpAdvancedReflection.dll

ุงู„ู€ FullName ุจูŠุญุชูˆูŠ ุนู„ู‰ ูƒุฐุง ู…ุนู„ูˆู…ุฉ: ุงู„ุงุณู…ุŒ ุงู„ู€ VersionุŒ ุงู„ู€ CultureุŒ ูˆุงู„ู€ PublicKeyToken.

ุทุจ ู„ูˆ ุนุงูŠุฒ ุชูุตู„ ุงู„ู…ุนู„ูˆู…ุงุช ุฏูŠ ูˆุชุงุฎุฏ ูƒู„ ุญุงุฌุฉ ู„ูˆุญุฏู‡ุงุŸ ููŠู‡ method ุงุณู…ู‡ุง GetName().

// Get an AssemblyName object with detailed information
AssemblyName assemblyName = assembly.GetName();
 
Console.WriteLine($"Name: {assemblyName.Name}");
Console.WriteLine($"Version: {assemblyName.Version}");

ุงู„ู€ method ุฏูŠ ุจุชุฑุฌุน object ู…ู† ู†ูˆุน AssemblyName ุฌูˆุงู‡ ุงู„ุชูุงุตูŠู„ ุฏูŠ ู…ุชูุตู„ุฉ. ูˆู„ูˆ ุนู…ู„ุช assemblyName.ToString() ู‡ูŠุฑุฌุนู„ูƒ ู†ูุณ ุงู„ู€ FullName ุงู„ู„ูŠ ุดูู†ุงู‡ ููˆู‚.

Entry vs. Calling vs. Executing Assembly

ุนุดุงู† ู†ูู‡ู… ุงู„ูุฑู‚ ุจูŠู† ุงู„ู€ methods ุงู„ู…ุฎุชู„ูุฉุŒ ู‡ู†ุนู…ู„ setup ุจุณูŠุท:

  1. ู‡ู†ุถูŠู class library ุจุฑูˆุฌูƒุช ุฌุฏูŠุฏ ูˆู†ุณู…ูŠู‡ MyFirstExtension.
  2. ู‡ู†ุถูŠู class library ุชุงู†ูŠ ูˆู†ุณู…ูŠู‡ MySecondExtension.

ุงู„ู‡ุฏู ู…ู†ู‡ู… ุฅู†ู†ุง ู†ูˆุถุญ ุงู„ูุฑู‚ ุจูŠู† GetEntryAssembly, GetCallingAssembly, ูˆ GetExecutingAssembly.

ู‡ู†ุนู…ู„ reference ูƒุงู„ุชุงู„ูŠ:

  • ุงู„ุจุฑูˆุฌูƒุช ุงู„ุฑุฆูŠุณูŠ (CsharpAdvancedReflection) ู‡ูŠุงุฎุฏ reference ู…ู† MyFirstExtension.
  • ุงู„ุจุฑูˆุฌูƒุช MyFirstExtension ู‡ูŠุงุฎุฏ reference ู…ู† MySecondExtension.
graph LR
    MainProject(CsharpAdvancedReflection) --> FirstExt(MyFirstExtension);
    FirstExt --> SecondExt(MySecondExtension);

ููŠ MyFirstExtensionุŒ ู‡ู†ุนู…ู„ class ุงุณู…ู‡ ReflectionDemo ูˆููŠู‡ method ุงุณู…ู‡ุง PrintAssemblyDetails.

ููŠ MySecondExtensionุŒ ู‡ู†ุนู…ู„ class ุงุณู…ู‡ ReflectionDemo2 ูˆููŠู‡ ู†ูุณ ุงู„ู€ method.

ุงู„ู€ method ุงู„ู„ูŠ ููŠ ReflectionDemo ู‡ุชู†ุงุฏูŠ ุนู„ู‰ ุงู„ู€ method ุงู„ู„ูŠ ููŠ ReflectionDemo2.

// In MyFirstExtension -> ReflectionDemo.cs
public static class ReflectionDemo
{
    public static void PrintAssemblyDetails()
    {
        // Call the method in the second extension
        MySecondExtension.ReflectionDemo2.PrintAssemblyDetails();
    }
}

ูˆููŠ ุงู„ุจุฑูˆุฌูƒุช ุงู„ุฑุฆูŠุณูŠุŒ ู‡ู†ู†ุงุฏูŠ ุนู„ู‰ ุงู„ู€ method ุงู„ู„ูŠ ููŠ MyFirstExtension.

// In Main Project -> Program.cs
MyFirstExtension.ReflectionDemo.PrintAssemblyDetails();

ุงู„ู€ call stack ู…ุงุดูŠ ุฅุฒุงูŠุŸ ุงู„ู€ CsharpAdvancedReflection ุจูŠู†ุงุฏูŠ MyFirstExtension ุงู„ู„ูŠ ุจุฏูˆุฑู‡ ุจูŠู†ุงุฏูŠ MySecondExtension.

ุฏู„ูˆู‚ุชูŠุŒ ุฌูˆู‡ ุงู„ู€ method ุงู„ู†ู‡ุงุฆูŠุฉ ููŠ ReflectionDemo2 ู‡ู†ุทุจุน ุจูŠุงู†ุงุช ุงู„ู€ Assemblies ุงู„ุชู„ุงุชุฉ.

// In MySecondExtension -> ReflectionDemo2.cs
public static void PrintAssemblyDetails()
{
    var entryAssembly = Assembly.GetEntryAssembly();
    var callingAssembly = Assembly.GetCallingAssembly();
    var executingAssembly = Assembly.GetExecutingAssembly();
 
    Console.WriteLine($"Entry Assembly: {entryAssembly.GetName().Name}");
    Console.WriteLine($"Calling Assembly: {callingAssembly.GetName().Name}");
    Console.WriteLine($"Executing Assembly: {executingAssembly.GetName().Name}");
}

ู„ู…ุง ู†ุดุบู„ ุงู„ูƒูˆุฏุŒ ุงู„ู†ุงุชุฌ ู‡ูŠูƒูˆู†:

Entry Assembly: CsharpAdvancedReflection
Calling Assembly: MyFirstExtension
Executing Assembly: MySecondExtension

ูƒุฏู‡ ูู‡ู…ู†ุง ุงู„ูุฑู‚:

  • ุงู„ู€ Entry Assembly: ู‡ูˆ ุงู„ู€ Assembly ุงู„ู„ูŠ ุจุฏุฃ ุชู†ููŠุฐ ุงู„ุฃุจู„ูƒูŠุดู† (ู…ู„ู ุงู„ู€ EXE ุนุงุฏุฉู‹).
  • ุงู„ู€ Calling Assembly: ู‡ูˆ ุงู„ู€ Assembly ุงู„ู„ูŠ ู†ุงุฏู‰ ุนู„ู‰ ุงู„ู€ method ุงู„ู„ูŠ ุจุชุชู†ูุฐ ุญุงู„ูŠู‹ุง. ููŠ ุญุงู„ุชู†ุงุŒ MyFirstExtension ู‡ูˆ ุงู„ู„ูŠ ู†ุงุฏู‰ ุนู„ู‰ PrintAssemblyDetails ุงู„ู„ูŠ ููŠ MySecondExtension.
  • ุงู„ู€ Executing Assembly: ู‡ูˆ ุงู„ู€ Assembly ุงู„ู„ูŠ ููŠู‡ ุงู„ูƒูˆุฏ ุงู„ู„ูŠ ุจูŠุชู†ูุฐ ุญุงู„ูŠู‹ุง.

Resources

Embedded Resources

ู‡ู†ู‚ูู„ ูƒู„ุงู…ู†ุง ุนู† ุงู„ู€ Assembly ุจู…ูˆุถูˆุน ุงู„ู€ Resources. ุงูุชุฑุถ ุฅู† ุงู„ุจุฑูˆุฌูƒุช ุจุชุงุนูƒ ู…ุญุชุงุฌ ูŠุฏุนู… ุงู„ุชุฑุฌู…ุฉ. ุฏู‡ ู…ุนู†ุงู‡ ุฅู†ูƒ ู…ุญุชุงุฌ dictionary ู„ูƒู„ ู„ุบุฉ. ุงู„ู…ู„ูุงุช ุฏูŠ ุงู„ู…ูุฑูˆุถ ุชูƒูˆู† ู…ูˆุฌูˆุฏุฉ ู…ุน ุงู„ุฃุจู„ูƒูŠุดู† ุจุชุงุนูƒ ุนุดุงู† ุชู‚ุฑุงู‡ุง ููŠ ุงู„ู€ run-time.

ุจุณ ููŠู‡ ู…ุดูƒู„ุฉ: ู„ูˆ ุงู„ู…ู„ู ู…ูˆุฌูˆุฏ ุฌู†ุจ ุงู„ุฃุจู„ูƒูŠุดู†ุŒ ุงู„ูŠูˆุฒุฑ ูŠู‚ุฏุฑ ูŠูุชุญู‡ ูˆูŠุนุฏู„ ููŠู‡ุŒ ูˆุงู†ุช ู…ุด ุนุงูŠุฒ ูƒุฏู‡. ุนุงูŠุฒ ุชุญู…ูŠ ู…ู„ูุงุช ุงู„ุชุฑุฌู…ุฉ ุฏูŠ.

ุฃุญุฏ ุงู„ุญู„ูˆู„ ู‡ูŠ ุงู„ู€ Embedded Resources. ุฅุฒุงูŠุŸ

ู‡ู†ุถูŠู ููˆู„ุฏุฑ ุฌุฏูŠุฏ ููŠ ุงู„ุจุฑูˆุฌูƒุช ุงู„ุฑุฆูŠุณูŠ ูˆู†ุณู…ูŠู‡ ResourcesุŒ ูˆุฌูˆุงู‡ ู‡ู†ุถูŠู ู…ู„ู ุชูƒุณุช ar.txt.

ู„ู…ุง ุชุฎุชุงุฑ ุงู„ู…ู„ู ุฏู‡ุŒ ู‡ุชู„ุงู‚ูŠ ููŠ ุงู„ู€ Properties ุจุชุงุนุชู‡ ุฎุงุตูŠุชูŠู† ู…ู‡ู…ูŠู†:

  1. ุงู„ู€ Copy to Output Directory: ุฏูŠ ุจุชุญุฏุฏ ู‡ู„ ุงู„ู…ู„ู ู‡ูŠุชู†ุณุฎ ู„ู„ููˆู„ุฏุฑ ุจุชุงุน ุงู„ู€ build ูˆู„ุง ู„ุฃ. ุงู„ู‚ูŠู…ุฉ ุงู„ุงูุชุฑุงุถูŠุฉ Do not copy. ู„ูˆ ุฎู„ูŠุชู‡ุง Copy alwaysุŒ ุงู„ู…ู„ู ู‡ูŠุชู†ุณุฎ ุฌู†ุจ ุงู„ู€ DLL ุจุชุงุนูƒ. ุจุณ ุฏู‡ ู…ุด ุงู„ู„ูŠ ุงุญู†ุง ุนุงูŠุฒูŠู†ู‡ุŒ ู„ุฅู† ุงู„ูŠูˆุฒุฑ ู‡ูŠู‚ุฏุฑ ูŠุดูˆูู‡.
  2. ุงู„ู€ Build Action: ุฏูŠ ุจุชุญุฏุฏ ุฅูŠู‡ ุงู„ุฅุฌุฑุงุก ุงู„ู„ูŠ ู‡ูŠุชุงุฎุฏ ู…ุน ุงู„ู…ู„ู ุฏู‡ ูˆู‚ุช ุงู„ู€ build. ุงู„ู‚ูŠู…ุฉ ุงู„ุงูุชุฑุงุถูŠุฉ None.

ุงู„ู„ูŠ ูŠู‡ู…ู†ุง ู‡ู†ุง ู‡ูˆ ู‚ูŠู…ุฉ Embedded Resource. ู„ูˆ ุงุฎุชุฑุชู‡ุง ูˆุนู…ู„ุช buildุŒ ุงู„ู…ู„ู ู…ุด ู‡ูŠุธู‡ุฑ ููŠ ุงู„ู€ output folderุŒ ู„ูƒู†ู‡ ู‡ูŠูƒูˆู† ุงุชุฏู…ุฌ ุฌูˆู‡ ู…ู„ู ุงู„ู€ DLL ู†ูุณู‡.

ู„ูˆ ุงุณุชุฎุฏู…ู†ุง ุฃุฏุงุฉ ุฒูŠ JetBrains dotPeek ุนุดุงู† ู†ูุชุญ ุงู„ู€ DLLุŒ ู‡ู†ู„ุงู‚ูŠ ููˆู„ุฏุฑ ุงุณู…ู‡ Resources ุธู‡ุฑ ุฌูˆู‡ ุงู„ู€ AssemblyุŒ ูˆุฌูˆุงู‡ ุงู„ู…ู„ู ุจุชุงุนู†ุง.

ุงู„ุงุณู… ุจุชุงุน ุงู„ู€ resource ุฏู‡ ู…ู‡ู… ุฌุฏู‹ุงุŒ ู„ุฅู†ูƒ ู‡ุชุณุชุฎุฏู…ู‡ ุนุดุงู† ุชูˆุตู„ ู„ู„ู…ู„ู ููŠ ุงู„ู€ run-time. ุงู„ุงุณู… ุจูŠูƒูˆู† ุจุงู„ุตูŠุบุฉ ุฏูŠ: ProjectName.FolderName.FileName

ูููŠ ุญุงู„ุชู†ุง ู‡ูŠูƒูˆู†: CsharpAdvancedReflection.Resources.ar.txt. ู…ู„ุญูˆุธุฉ: ุงู„ุงุณู… ุฏู‡ case-sensitiveุŒ ูŠุนู†ูŠ ุงู„ุญุฑูˆู ุงู„ูƒุงุจูŠุชุงู„ ูˆุงู„ุณู…ูˆู„ ุจุชูุฑู‚.

Reading Embedded Resources

ุฏู„ูˆู‚ุชูŠ ุฃู†ุง ุนุงูŠุฒ ุฃู‚ุฑุฃ ู…ุญุชูˆูŠุงุช ุงู„ู…ู„ู ุฏู‡ ูˆุฃุทุจุนู‡ุง ููŠ ุงู„ู€ Console.

ู„ุงุฒู… ู†ู‚ุฑุฃ ุงู„ู€ resource ู…ู† ู†ูุณ ุงู„ู€ Assembly ุงู„ู„ูŠ ู‡ูˆ ุฌูˆุงู‡.

// Get the current assembly
Assembly assembly = Assembly.GetExecutingAssembly();
 
// Define the resource name
string resourceName = "CsharpAdvancedReflection.Resources.ar.txt";
 
// Get the resource as a stream
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
    if (stream == null)
    {
        Console.WriteLine("Resource not found!");
        return;
    }
 
    Console.WriteLine("Resource found!");
 
    // Use a StreamReader to read the content
    using (StreamReader reader = new StreamReader(stream))
    {
        string content = reader.ReadToEnd();
        Console.WriteLine(content);
    }
}

ุงูŠู‡ ู‡ูˆ ุงู„ู€ StreamุŸ ุจุงุฎุชุตุงุฑ ุดุฏูŠุฏุŒ ู‡ูˆ ุขู„ูŠุฉ ุจุชู…ูƒู†ูƒ ู…ู† ู‚ุฑุงุกุฉ ูˆูƒุชุงุจุฉ ุงู„ุจูŠุงู†ุงุช ููŠ ุฃูŠ ู…ูƒุงู† (ู…ู„ูุŒ ู…ูŠู…ูˆุฑูŠุŒ ุฏุงุชุงุจูŠุฒุŒ ุฅู„ุฎ). ุงู„ู€ method ุงู„ู„ูŠ ุงุณู…ู‡ุง GetManifestResourceStream ุจุชุฑุฌุนู„ูƒ stream object ู„ู„ู…ู„ู ุงู„ู„ูŠ ุญุฏุฏุชู‡.

ุงู„ู€ stream ุฏู‡ ุจูŠุฏูŠู„ูƒ access ุนู„ู‰ ุงู„ู€ Bytes ุจุชุงุนุฉ ุงู„ู…ู„ู. ูƒู„ ู…ู„ู ููŠ ุงู„ุขุฎุฑ ู‡ูˆ ุนุจุงุฑุฉ ุนู† ุดูˆูŠุฉ bytes ุฌู†ุจ ุจุนุถ. ุจู†ู‚ุฏุฑ ู†ู‚ุฑุฃ ุงู„ู€ bytes ุฏูŠ ูˆู†ุญูˆู„ู‡ุง ู„ู€ characters.

ููŠ ุงู„ูƒูˆุฏ ุงู„ู„ูŠ ููˆู‚ุŒ ุงุณุชุฎุฏู…ู†ุง StreamReader ุนุดุงู† ูŠุณู‡ู„ ุนู„ูŠู†ุง ุนู…ู„ูŠุฉ ุงู„ู‚ุฑุงุกุฉ ูˆุชุญูˆูŠู„ ุงู„ู€ bytes ู„ู†ุต.

ู„ูˆ ุบูŠุฑู†ุง ุญุฑู ูˆุงุญุฏ ููŠ ุงุณู… ุงู„ู€ resource (ู…ุซู„ุงู‹ ุฎู„ูŠู†ุงู‡ ูƒุงุจูŠุชุงู„ ูˆู‡ูˆ ุณู…ูˆู„)ุŒ ุงู„ู€ stream ู‡ูŠุฑุฌุน null ูˆู‡ุชุธู‡ุฑ ุฑุณุงู„ุฉ โ€œResource not found!โ€œ.

ุฏู‡ ูƒุฏู‡ ุงู„ุฌุฒุก ุงู„ุฃูˆู„ ู…ู† ุงู„ููŠุฏูŠูˆ. ุดูˆูู†ุง ุฅูŠู‡ ู‡ูˆ ุงู„ู€ AssemblyุŒ ูˆุงู„ูุฑู‚ ุจูŠู† ุทุฑู‚ ุงู„ุญุตูˆู„ ุนู„ูŠู‡ุŒ ูˆุฅุฒุงูŠ ู†ุนู…ู„ embedded resource ูˆู†ู‚ุฑุฃู‡. ููŠ ุงู„ุฌุฒุก ุงู„ุฌุงูŠุŒ ู‡ู†ุฏุฎู„ ููŠ ุนู…ู‚ ุงู„ู€ Reflection ูˆู†ุดูˆู ุงู„ู‚ูˆุฉ ุงู„ุญู‚ูŠู‚ูŠุฉ ุงู„ู„ูŠ ุจูŠุฏูŠู‡ุง ู„ูŠู†ุง.

Inspecting Types and Dynamic Invocation

ู‚ูˆู„ู†ุง ุฅู† ุงู„ู€ Assembly ู‡ูˆ ุจูˆุงุจุฉ ุงู„ู‚ุตุฑ ุงู„ูƒุจูŠุฑุฉ. ุงู„ู€ Assembly ุฏู‡ ู‡ูˆ ุงู„ุจุฑูˆุฌูƒุช ุจุชุงุนูƒ ุจุนุฏ ู…ุง ูŠุชุนู…ู„ู‡ build.

ุฌูˆู‡ ุงู„ุจุฑูˆุฌูƒุช ุฏู‡ ููŠู‡ ุฅูŠู‡ุŸ ููŠู‡ types ุฒูŠ classes, interfaces, structs. ูˆุฌูˆู‡ ูƒู„ type ููŠู‡ methods, properties, fields, ูˆ events.

ูุจุนุฏ ู…ุง ุฏุฎู„ู†ุง ู…ู† ุงู„ุจูˆุงุจุฉ ุงู„ูƒุจูŠุฑุฉ (Assembly)ุŒ ู‚ุฏุงู…ู†ุง ุฏู„ูˆู‚ุชูŠ ุฃุจูˆุงุจ ุงู„ุบุฑู ุงู„ู„ูŠ ุฌูˆู‡ ุงู„ู‚ุตุฑุŒ ูˆุงู„ู„ูŠ ู‡ูŠ ุงู„ู€ Types. ุนุดุงู† ุฃู‚ุฏุฑ ุฃุฏุฎู„ ุฃูŠ ุบุฑูุฉุŒ ู…ุญุชุงุฌ ุฃูˆุตู„ ู„ู„ู€ Type ุจุชุงุนู‡ุง ุงู„ุฃูˆู„.

Getting a Type Object

ุงุชูƒู„ู…ู†ุง ู‚ุจู„ ูƒุฏู‡ ุฅู† ูƒู„ ุงู„ุฃู†ูˆุงุน ููŠ ุงู„ู€ .NET ุจุชูˆุฑุซ ู…ู† parent ูˆุงุญุฏ ุฑุฆูŠุณูŠ ู‡ูˆ Object. ูˆููŠ ุงู„ู€ Object class ุฏู‡ุŒ ููŠู‡ method ุงุณู…ู‡ุง GetType().

object obj = new object();
Type objectType = obj.GetType();

ุงู„ู€ method ุฏูŠ ุจุชุฑุฌุน object ู…ู† ู†ูˆุน ุงุณู…ู‡ Type. ุงู„ู€ Type ุฏู‡ ู‡ูˆ ุจุงุจ ุงู„ุบุฑูุฉ ุงู„ู„ูŠ ู„ู…ุง ุชูุชุญู‡ ู‡ุชู‚ุฏุฑ ุชุดูˆู ูƒู„ ุงู„ูƒู†ูˆุฒ ุงู„ู„ูŠ ุฌูˆุงู‡ุง.

ู„ุงุฒู… ุชุญุท ููŠ ุฏู…ุงุบูƒ ุฅู†ู†ุง ูƒู„ ุฏู‡ ุจู†ุชุนุงู…ู„ ู…ุน assembly ูˆูƒูˆุฏ ููŠ ุงู„ู€ run-timeุŒ ู…ุด ููŠ ุงู„ู€ compile-time. ูŠุนู†ูŠ ุฅูŠู‡ุŸ ูŠุนู†ูŠ ุชุฎูŠู„ ุฅู†ูƒ ู…ุด ู…ุนุงูƒ reference ู„ู„ู€ assembly ุฏู‡ ุฃุตู„ู‹ุงุŒ ูˆู…ุน ุฐู„ูƒ ุจุชู‚ุฏุฑ ุชุชุนุงู…ู„ ู…ุนุงู‡. ู‡ูˆ ุฏู‡ ุฏูˆุฑ ุงู„ู€ Reflection.

ุทูŠุจุŒ ุฅุฒุงูŠ ู†ูˆุตู„ ู„ู„ู€ Type ุฏู‡ุŸ ุงู„ู€ Assembly ู†ูุณู‡ ุฌูˆุงู‡ method ุงุณู…ู‡ุง GetTypes()ุŒ ูˆุฏูŠ ุจุชุฑุฌุนู„ูƒ ูƒู„ ุงู„ู€ types ุงู„ู„ูŠ ู…ุชุนุฑูุฉ ุฌูˆุงู‡.

public class Employee { }
public class Product { }
 
// ... in Main method
Assembly assembly = Assembly.GetExecutingAssembly();
Type[] types = assembly.GetTypes();
 
foreach (var type in types)
{
    Console.WriteLine($"Type Name: {type.FullName}");
}

ู‡ู†ุง ุนู…ู„ู†ุง loop ุนู„ู‰ ูƒู„ ุงู„ู€ types ุงู„ู„ูŠ ููŠ ุงู„ู€ Assembly ุงู„ุญุงู„ูŠ.

ู…ู† ุงู„ู€ Type object ุฏู‡ุŒ ุชู‚ุฏุฑ ุชุนุฑู ูƒู„ ุชูุงุตูŠู„ู‡:

foreach (var type in types)
{
    Console.WriteLine($"Name: {type.Name}");
    Console.WriteLine($"Is Public: {type.IsPublic}");
    // Use ?. to avoid null error if it has no base
    Console.WriteLine($"Base Type: {type.BaseType?.Name}"); 
    Console.WriteLine("----------------");
}

ุจุงู„ุทุฑูŠู‚ุฉ ุฏูŠุŒ ุจุชู‚ุฏุฑ ุชุนุฑู ุงุณู… ุงู„ู€ TypeุŒ ู‡ูˆ public ูˆู„ุง ู„ุฃุŒ ูˆุจูŠูˆุฑุซ ู…ู† ู…ูŠู† (BaseType)ุŒ ูˆู‡ู„ ู‡ูˆ sealed ุฃูˆ genericุŒ ูˆูƒู„ ุญุงุฌุฉ ุชุงู†ูŠุฉ. ุฏูŠ ุงู„ู„ูŠ ุจู†ุณู…ูŠู‡ุง ุงู„ู€ Metadata ุจุชุงุนุฉ ุงู„ู€ Type.

ููŠู‡ method ุชุงู†ูŠุฉ ุงุณู…ู‡ุง GetExportedTypes() ูˆุฏูŠ ุจุชุฑุฌุน ุงู„ู€ public types ุจุณุŒ ุนู„ู‰ ุนูƒุณ GetTypes() ุงู„ู„ูŠ ุจุชุฑุฌุน ูƒู„ู‡.

ููŠู‡ ุทุฑู‚ ุชุงู†ูŠุฉ ุนุดุงู† ุชุฌูŠุจ ุงู„ู€ Type:

  • ู„ูˆ ู…ุนุงูƒ variableุŒ ู…ู…ูƒู† ุชุณุชุฎุฏู… variable.GetType().
  • ู„ูˆ ุนุงูŠุฒ Type ู…ุนูŠู† ุจุงุณู…ู‡ุŒ ู…ู…ูƒู† ุชุณุชุฎุฏู… typeof() keyword.
Type stringType = typeof(string);
Type intType = typeof(int);

Inspecting Type Members

ุฏู„ูˆู‚ุชูŠ ุจุนุฏ ู…ุง ูุชุญู†ุง ุจุงุจ ุงู„ุบุฑูุฉ (Type)ุŒ ุนุงูŠุฒูŠู† ู†ุดูˆู ุงู„ูƒู†ูˆุฒ ุงู„ู„ูŠ ุฌูˆุงู‡ุง. ุงู„ู€ Type class ููŠู‡ method ุงุณู…ู‡ุง GetMembers()ุŒ ูˆุฏูŠ ุจุชุฑุฌุน ูƒู„ ุงู„ู€ code members ุงู„ู„ูŠ ุฌูˆู‡ ุงู„ู€ Type ุฏู‡ (ุณูˆุงุก method, property, field, event, constructor, ุฃูŠ ุญุงุฌุฉ).

Type dateTimeType = typeof(DateTime);
MemberInfo[] members = dateTimeType.GetMembers();
 
foreach (var member in members)
{
    Console.WriteLine($"Name: {member.Name}, Member Type: {member.MemberType}");
}

ู‡ุชู„ุงุญุธ ุฅู† methods ุฒูŠ Parse ุจุชุชูƒุฑุฑ ูƒุฐุง ู…ุฑุฉ. ุฏู‡ ุจุณุจุจ ุงู„ู€ Method Overloadingุ› ูƒู„ overload ุจูŠุนุชุจุฑ member ู…ู†ูุตู„.

ุงู„ู€ GetMembers() ุจุชุฑุฌุน ูƒู„ ุงู„ู€ members ุจุบุถ ุงู„ู†ุธุฑ ู‡ูŠ static ูˆู„ุง instance.

Filtering Members with BindingFlags

ู„ูˆ ุนุงูŠุฒ ุชูู„ุชุฑ ุงู„ู†ุชุงูŠุฌุŒ ููŠู‡ overload ุชุงู†ูŠ ู„ู„ู€ method ุฏูŠ ุจูŠุงุฎุฏ enum ุงุณู…ู‡ BindingFlags. ุฏูŠ ุนุจุงุฑุฉ ุนู† flags ุจุชุญุฏุฏ ุจูŠู‡ุง ุฅูŠู‡ ุงู„ู„ูŠ ุงู†ุช ุนุงูŠุฒู‡ ุจุงู„ุธุจุท.

// Get only PUBLIC INSTANCE members
var instanceMembers = dateTimeType.GetMembers(BindingFlags.Public | BindingFlags.Instance);
 
// Get only PUBLIC STATIC members
var staticMembers = dateTimeType.GetMembers(BindingFlags.Public | BindingFlags.Static);
 
// Get NON-PUBLIC STATIC members (private, internal, etc.)
var nonPublicStaticMembers = dateTimeType.GetMembers(BindingFlags.NonPublic | BindingFlags.Static);

ู„ุงุญุธ ุฅู†ู†ุง ุจู†ุณุชุฎุฏู… | (single pipe)ุŒ ูˆุฏู‡ ุงู„ู€ bitwise OR operator ุงู„ู„ูŠ ุจู†ุณุชุฎุฏู…ู‡ ุนุดุงู† ู†ุฏู…ุฌ ุงู„ู€ flags ู…ุน ุจุนุถ.

ุจุงู„ุทุฑูŠู‚ุฉ ุฏูŠุŒ ุชู‚ุฏุฑ ุชุดูˆู ุญุชู‰ ุงู„ู€ private members ุงู„ู„ูŠ ููŠ ุงู„ุนุงุฏูŠ ู…ุด ุจุชู‚ุฏุฑ ุชูˆุตู„ู‡ุง. ูˆุดูˆูŠุฉ ูˆู‡ู†ุนุฑู ุฅุฒุงูŠ ู†ู†ูุฐ private method ูƒู…ุงู†!

ู„ูˆ ุนุงูŠุฒ ุชุฌูŠุจ ู†ูˆุน ู…ุนูŠู† ู…ู† ุงู„ู€ membersุŒ ููŠู‡ methods ู…ุฎุตุตุฉ ุจุชุณู‡ู„ ุนู„ูŠูƒ ุงู„ู…ูˆุถูˆุน:

  • GetMethods()
  • GetProperties()
  • GetFields()
  • GetConstructors()

ู…ุซู„ุงู‹ุŒ ุนุดุงู† ู†ุนุฑู ู‡ู„ ุงู„ู€ property ุฏูŠ read-only ูˆู„ุง ู„ุฃุŒ ู…ู…ูƒู† ู†ุดูˆู ู‡ู„ ู„ูŠู‡ุง set method ูˆู„ุง ู„ุฃ.

var properties = dateTimeType.GetProperties();
foreach (var prop in properties)
{
    bool isReadOnly = !prop.CanWrite;
    Console.WriteLine($"Property: {prop.Name}, Is Read-Only: {isReadOnly}");
}

Getting Method Parameters

ุจุนุฏ ู…ุง ุฌุจู†ุง ุงู„ู€ methodsุŒ ู…ู…ูƒู† ูƒู…ุงู† ู†ุนุฑู ุฅูŠู‡ ุงู„ู€ parameters ุงู„ู„ูŠ ูƒู„ method ุจุชุงุฎุฏู‡ุง.

// Get a specific method by name
MethodInfo addDaysMethod = dateTimeType.GetMethod("AddDays");
 
if (addDaysMethod != null)
{
    // Get its parameters
    ParameterInfo[] parameters = addDaysMethod.GetParameters();
    foreach (var param in parameters)
    {
        Console.WriteLine($"Parameter Name: {param.Name}, Type: {param.ParameterType.Name}");
    }
}

ุจุงู„ุทุฑูŠู‚ุฉ ุฏูŠุŒ ุจุชู‚ุฏุฑ ุชุดุฑุญ ุงู„ู€ DLL ูˆุชุนุฑู ูƒู„ ุชูุงุตูŠู„ู‡ ู…ู† ุบูŠุฑ ู…ุง ูŠูƒูˆู† ู…ุนุงูƒ ุงู„ุณูˆุฑุณ ูƒูˆุฏ.

Invoking Methods Dynamically

ู„ุญุฏ ู‡ู†ุง ุฅุญู†ุง ุจู†ู‚ุฑุฃ ู…ุนู„ูˆู…ุงุช ุจุณ. ุงู„ุงุณุชูุงุฏุฉ ุงู„ุฃูƒุจุฑ ู…ู† ุงู„ู€ Reflection ู‡ูŠ ุฅู†ู†ุง ู†ู‚ุฏุฑ ู†ุชูุงุนู„ ู…ุน ุงู„ู€ Type ุฏู‡ุŒ ูŠุนู†ูŠ ู†ู†ูุฐ ุงู„ู€ methods ุจุชุงุนุชู‡ ุจุดูƒู„ ุฏูŠู†ุงู…ูŠูƒูŠ ุจุงุณุชุฎุฏุงู… method ุงุณู…ู‡ุง Invoke().

Invoking a Static Method

ุงู„ู€ static method ู…ุด ู…ุญุชุงุฌุฉ instance ู…ู† ุงู„ู€ class ุนุดุงู† ุชุชู†ูุฐ.

Type mathType = typeof(Math);
MethodInfo minMethod = mathType.GetMethod("Min", new Type[] { typeof(int), typeof(int) });
 
// Parameters for the method
object[] parameters = { 5, 10 };
 
// Invoke the static method. First argument is null because it's static.
object result = minMethod.Invoke(null, parameters);
 
Console.WriteLine($"The minimum is: {result}"); // Output: 5

ุงู„ู€ Invoke method ุจุชุงุฎุฏ 2 parameters:

  1. ุงู„ู€ instance ุงู„ู„ูŠ ู‡ุชู†ูุฐ ุนู„ูŠู‡ ุงู„ู€ method. ููŠ ุญุงู„ุฉ ุงู„ู€ static methodุŒ ุจู†ุจุนุช null.
  2. ุงู„ู€ Array of objects ุจูŠู…ุซู„ ุงู„ู€ parameters ุงู„ู„ูŠ ุงู„ู€ method ู…ุญุชุงุฌุงู‡ุง.

Invoking an Instance Method

ุงู„ู€ instance method ู„ุงุฒู… ุชุชู†ูุฐ ุนู„ู‰ object ู…ุนูŠู†.

DateTime today = DateTime.Now;
Type dateTimeType = typeof(DateTime);
MethodInfo addDaysMethod = dateTimeType.GetMethod("AddDays");
 
// Parameters for the AddDays method
object[] parameters = { 10.0 }; // Add 10 days
 
// Invoke the method on the 'today' instance
// Note: DateTime is immutable, so AddDays returns a new instance
object newDate = addDaysMethod.Invoke(today, parameters);
 
Console.WriteLine($"Original Date: {today}");
Console.WriteLine($"New Date: {newDate}");

ู‡ู†ุง ุจุนุชู†ุง ุงู„ู€ today object ูƒุฃูˆู„ parameter ู„ู„ู€ Invoke ุนุดุงู† ูŠุนุฑู ูŠู†ูุฐ ุงู„ู€ method ุฏูŠ ุนู„ู‰ ู…ูŠู†.

Practical Use Cases for Reflection

ุฏู„ูˆู‚ุชูŠ ุงู„ุตูˆุฑุฉ ู‡ุชุจุฏุฃ ุชูˆุถุญ ุฃูƒุชุฑ ู„ู…ุง ู†ุดูˆู ุฃู…ุซู„ุฉ ุนู…ู„ูŠุฉ.

Use Case 1: Building a Plugin System

ุจุฑุงู…ุฌ ุฒูŠ Visual Studio ูˆ VS Code ุจุชุณุชุฎุฏู… extensions ุนุดุงู† ุชุฒูˆุฏ features. ุงู„ู€ extensions ุฏูŠ ุจุชุดุชุบู„ ุฅุฒุงูŠุŸ ุจุงู„ู€ Reflection.

ุงู„ููƒุฑุฉ ุฅู† ุงู„ุฃุจู„ูƒูŠุดู† ุงู„ุฃุณุงุณูŠ ุจูŠุนู…ู„ scan ู„ููˆู„ุฏุฑ ู…ุนูŠู†ุŒ ูŠู„ุงู‚ูŠ ููŠู‡ ู…ู„ูุงุช DLL (ุงู„ู€ plugins)ุŒ ูˆูŠุณุชุฎุฏู… ุงู„ู€ Reflection ุนุดุงู† ูŠุญู…ู„ ุงู„ู€ assemblies ุฏูŠ ููŠ ุงู„ู€ run-timeุŒ ูˆุจุนุฏูŠู† ูŠุจุฏุฃ ูŠุดูˆู ุฅูŠู‡ ุงู„ู€ classes ูˆุงู„ู€ methods ุงู„ู„ูŠ ุฌูˆุงู‡ุง ูˆูŠู†ูุฐู‡ุง.

sequenceDiagram
    participant App as Main App
    participant FS as File System
    participant Reflector as Reflection
    participant Plugin as Plugin.dll

    App->>FS: Scan "Plugins" folder for DLLs
    FS-->>App: Found Plugin.dll
    App->>Reflector: Assembly.LoadFrom("Plugin.dll")
    Reflector-->>App: Loaded Assembly
    App->>Reflector: assembly.GetType("Plugin.EntryPoint")
    Reflector-->>App: Found Type
    App->>Reflector: type.GetMethod("Initialize")
    Reflector-->>App: Found Method
    App->>Plugin: method.Invoke()
    Plugin-->>App: Plugin Initialized!

ุจุงู„ูƒูˆุฏุŒ ุงู„ู…ูˆุถูˆุน ู…ู…ูƒู† ูŠุจู‚ู‰ ูƒุฏู‡:

string pluginsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Extensions");
string[] pluginFiles = Directory.GetFiles(pluginsPath, "*.dll");
 
foreach (var file in pluginFiles)
{
    // 1. Load the assembly
    Assembly pluginAssembly = Assembly.LoadFrom(file);
    
    // 2. Find the entry point type (assuming a convention)
    // The full name is needed: Namespace.TypeName
    string typeName = $"{pluginAssembly.GetName().Name}.EntryPoint";
    Type entryPointType = pluginAssembly.GetType(typeName);
 
    if (entryPointType != null)
    {
        // 3. Find the initialization method
        MethodInfo initializeMethod = entryPointType.GetMethod("Initialize");
 
        if (initializeMethod != null)
        {
            // 4. Invoke the method
            initializeMethod.Invoke(null, null); // Assuming it's a static method with no parameters
        }
    }
}

ุจูƒุฏู‡ุŒ ุฃู†ุช ุนู…ู„ุช ุณูŠุณุชู… ุจูŠู‚ุฑุฃ extensions ูˆูŠุดุบู„ู‡ุง ููŠ ุงู„ู€ run-time ู…ู† ุบูŠุฑ ู…ุง ุชูƒูˆู† ุนุงุฑู ุนู†ู‡ุง ุฃูŠ ุญุงุฌุฉ ูˆู‚ุช ุงู„ู€ compile-time.

Use Case 2: Dynamic Object Mapping

ุนู…ู„ูŠุฉ ู†ุณุฎ ุงู„ุฏุงุชุง ู…ู† object ู„ู€ object ุชุงู†ูŠ (ุฎุตูˆุตู‹ุง ู…ู† ุฃู†ูˆุงุน ู…ุฎุชู„ูุฉ) ุงุณู…ู‡ุง mapping. ุงู„ู…ูƒุชุจุงุช ุงู„ู…ุดู‡ูˆุฑุฉ ุฒูŠ AutoMapper ุจุชุณุชุฎุฏู… ุงู„ู€ Reflection ุจูƒุซุงูุฉ.

ู†ู‚ุฏุฑ ู†ุนู…ู„ mapper ุจุณูŠุท ุฌุฏู‹ุง ุจุงู„ู€ Reflection:

public static void MapProperties(object source, object destination)
{
    Type sourceType = source.GetType();
    Type destType = destination.GetType();
 
    PropertyInfo[] sourceProps = sourceType.GetProperties();
 
    foreach (var sourceProp in sourceProps)
    {
        // Find a property with the same name in the destination object
        PropertyInfo destProp = destType.GetProperty(sourceProp.Name);
 
        // Check if the destination property exists and is writable
        if (destProp != null && destProp.CanWrite)
        {
            // Get value from source and set it on destination
            object value = sourceProp.GetValue(source);
            destProp.SetValue(destination, value);
        }
    }
}

ุงู„ู€ method ุฏูŠุŒ ููŠ 3 ุณุทูˆุฑ logicุŒ ุจุชู‚ุฏุฑ ุชู†ุณุฎ ุงู„ู‚ูŠู… ุจูŠู† ุฃูŠ ุงุชู†ูŠู† objects ุทุงู„ู…ุง ุฃุณู…ุงุก ุงู„ู€ properties ู…ุชุดุงุจู‡ุฉุŒ ุญุชู‰ ู„ูˆ ูƒุงู†ูˆุง ู…ู† ุฃู†ูˆุงุน ู…ุฎุชู„ูุฉ ุชู…ุงู…ู‹ุง. ุฏู‡ ู…ุซุงู„ ูˆุงุถุญ ุฌุฏู‹ุง ุนู„ู‰ ู‚ูˆุฉ ูˆู…ุฑูˆู†ุฉ ุงู„ู€ Reflection.

Conclusion

ุงู„ู€ Reflection ู…ุณุชุฎุฏู… ููŠ ุญุงุฌุงุช ูƒุชูŠุฑ ุฌุฏู‹ุง ููŠ ุนุงู„ู… ุงู„ู€ .NET:

  • ุงู„ู€ Dependency Injection (DI) Containers: ุจุชุณุชุฎุฏู…ู‡ ุนุดุงู† ุชูƒุชุดู ุงู„ู€ services ูˆุชุนู…ู„ู‡ุง instantiate.
  • ุงู„ู€ Object-Relational Mappers (ORMs): ุฒูŠ Entity FrameworkุŒ ุจูŠุณุชุฎุฏู…ู‡ ุนุดุงู† ูŠุนู…ู„ map ู„ู„ุฏุงุชุง ุงู„ู„ูŠ ุฌุงูŠุฉ ู…ู† ุงู„ุฏุงุชุงุจูŠุฒ ู„ู„ู€ C# objects.
  • ุงู„ู€ Serialization Libraries: ุฒูŠ Newtonsoft.JsonุŒ ุจุชุณุชุฎุฏู…ู‡ ุนุดุงู† ุชู‚ุฑุฃ ุงู„ู€ properties ูˆุชุญูˆู„ ุงู„ู€ object ู„ู€ JSON ูˆุงู„ุนูƒุณ.
  • ุงู„ู€ Unit Testing Frameworks: ุจุชุณุชุฎุฏู…ู‡ ุนุดุงู† ุชูƒุชุดู ุงู„ู€ Test methods ูˆุชุดุบู„ู‡ุง.

A Note on Attributes

ุขุฎุฑ ุญุงุฌุฉ ุงู„ู€ Attributes. ู‡ูŠ ุนุจุงุฑุฉ ุนู† โ€œุนู„ุงู…ุฉโ€ ุฃูˆ metadata ุฅุถุงููŠุฉ ุจุชุญุทู‡ุง ุนู„ู‰ ุงู„ูƒูˆุฏ ุจุชุงุนูƒ (ุฒูŠ class ุฃูˆ method).

[Serializable]
public class MyData
{
    [Required]
    public string Name { get; set; }
}

ุงู„ู€ attributes ุฏูŠ ููŠ ุญุฏ ุฐุงุชู‡ุง ู…ุด ุจุชุนู…ู„ ุญุงุฌุฉ. ู‡ูŠ ู…ุฌุฑุฏ ู…ุนู„ูˆู…ุงุช. ุงู„ู€ Reflection ู‡ูˆ ุงู„ุฃุฏุงุฉ ุงู„ู„ูŠ ุจุชุฎู„ูŠูƒ ุชู‚ุฑุฃ ุงู„ู€ metadata ุฏูŠ ููŠ ุงู„ู€ run-time ูˆุชุงุฎุฏ action ุจู†ุงุกู‹ ุนู„ูŠู‡ุง.

// Check if a type has a specific attribute
bool isSerializable = typeof(MyData).IsDefined(typeof(SerializableAttribute), false);

ุงู„ู€ Reflection ู…ูˆุถูˆุน ู‚ูˆูŠ ุฌุฏู‹ุงุŒ ูˆูู‡ู…ู‡ ุจูŠูุชุญู„ูƒ ุฃุจูˆุงุจ ูƒุชูŠุฑ ูˆุจูŠุฎู„ูŠูƒ ุชูู‡ู… ุฅุฒุงูŠ ุงู„ุฃุฏูˆุงุช ูˆุงู„ู…ูƒุชุจุงุช ุงู„ู„ูŠ ุจุชุณุชุฎุฏู…ู‡ุง ูƒู„ ูŠูˆู… ุดุบุงู„ุฉ ู…ู† ุฌูˆู‡.