C# - 反射:初學者的指南

您好,未來的編程超級明星!今天,我們將踏上一段令人興奮的旅程,進入 C# 反射的世界。別擔心如果您之前從未寫過一行代碼——我將成為您的友好導遊,我們將一起探索這個主題,一步一步地。在這個教學的結尾,您將對反射有堅實的了解,並知道如何使用它。那麼,讓我們開始吧!

C# - Reflection

什麼是反射?

想像您在一家豪華餐廳,有人遞給您一份菜單。但這不是一般的菜單——它是神奇的!您不僅可以看到各種菜肴,還可以窺視廚房,看看它們是如何製作的,使用了哪些食材,甚至可以即時修改菜譜。這就是 C# 中的反射在做的事情,只是對代碼而不是食物。

從技術角度來說,反射是 C# 的一個特點,它允許程序在運行時檢查、交互和修改自己的結構和行為。這就像是給您的程序一面镜子,讓它看見自己!

反射的應用

現在,您可能會想,“為什麼我要讓我的程序看見自己?”這個問題問得好!讓我們探討一些反射的實際應用:

  1. 動態加載程序集:反射允許您加載和使用在編寫程序時可能未知程序集(可以將這些看作是代碼包)。

  2. 創建類型的實例:您可以在編譯時不知道確切類型的情況下創建特定類型的對象。

  3. 調用方法:反射使您能夠動態地調用對象上的方法。

  4. 訪問和修改字段和屬性:您可以讀取和寫入對象的字段和屬性。

  5. 屬性檢查:您可以檢查附加在各種程序元素上的屬性(額外信息)。

讓我們通過一些代碼示例來更詳細地看看這些!

示例 1:動態創建實例

using System;
using System.Reflection;

class Program
{
static void Main()
{
// 獲取 string 類型的類型
Type stringType = typeof(string);

// 使用反射創建 string 的實例
object str = Activator.CreateInstance(stringType, new object[] { "Hello, Reflection!" });

Console.WriteLine(str); // 輸出: Hello, Reflection!
}
}

在這個示例中,我們使用反射來創建 string 類型的實例。這就像是告訴 C#,“我想創建一些東西,但我在運行時告訴你它是什么。”這在您在程序運行時不知道需要創建的確切類型時特別有用。

示例 2:動態調用方法

using System;
using System.Reflection;

class MyClass
{
public void SayHello(string name)
{
Console.WriteLine($"Hello, {name}!");
}
}

class Program
{
static void Main()
{
// 創建 MyClass 的實例
MyClass obj = new MyClass();

// 獲取 MyClass 的類型
Type type = obj.GetType();

// 獲取 SayHello 方法的 MethodInfo
MethodInfo methodInfo = type.GetMethod("SayHello");

// 調用方法
methodInfo.Invoke(obj, new object[] { "Reflection" });
// 輸出: Hello, Reflection!
}
}

在這裡,我們使用反射來在我們的 MyClass 對象上調用 SayHello 方法。這就像是告訴 C#,“我知道這個對象有一個名為 'SayHello' 的方法,請為我調用它。”當您需要在編譯時不知道確切類型的對象上調用方法時,這非常有用。

查看元數據

反射最酷的事情之一就是它讓我們能夠窺視代碼底層。我們可以查看類型、方法、屬性等的元數據。讓我們看看!

示例 3:查看類型元數據

using System;
using System.Reflection;

class Program
{
static void Main()
{
Type stringType = typeof(string);

Console.WriteLine($"類型名稱: {stringType.Name}");
Console.WriteLine($"完整名稱: {stringType.FullName}");
Console.WriteLine($"命名空間: {stringType.Namespace}");
Console.WriteLine($"它是一個類?{stringType.IsClass}");
Console.WriteLine($"基類型: {stringType.BaseType}");

Console.WriteLine("\n方法:");
foreach (MethodInfo method in stringType.GetMethods())
{
Console.WriteLine(method.Name);
}
}
}

這段代碼就像是在問 string 類型告訴我們所有關於它自己的信息。我們正在了解它的名稱、它所屬的命名空間、它是否是一個類、它從哪裡繼承,甚至列出了它所有的方法。這就像與我們的代碼進行對話!

一個綜合示例

讓我們將所有這些東西結合起來,用一個更複雜的示例來展示反射的各個方面:

using System;
using System.Reflection;

public class Person
{
public string Name { get; set; }
public int Age { get; set; }

public Person(string name, int age)
{
Name = name;
Age = age;
}

public void Introduce()
{
Console.WriteLine($"Hi, I'm {Name} and I'm {Age} years old.");
}
}

class Program
{
static void Main()
{
// 使用反射創建 Person 對象
Type personType = typeof(Person);
object[] constructorArgs = { "Alice", 30 };
Person person = (Person)Activator.CreateInstance(personType, constructorArgs);

// 使用反射獲取和設定屬性值
PropertyInfo nameProperty = personType.GetProperty("Name");
PropertyInfo ageProperty = personType.GetProperty("Age");

Console.WriteLine($"當前名稱: {nameProperty.GetValue(person)}");
nameProperty.SetValue(person, "Bob");
ageProperty.SetValue(person, 25);

// 使用反射調用方法
MethodInfo introduceMethod = personType.GetMethod("Introduce");
introduceMethod.Invoke(person, null);

// 顯示 Person 類的所有方法
Console.WriteLine("\nPerson 類的方法:");
foreach (MethodInfo method in personType.GetMethods())
{
Console.WriteLine(method.Name);
}
}
}

這個示例演示了使用反射創建對象、獲取和設定屬性值、調用方法和列舉類的所有方法。這就像我們完全通過反射操控 Person 對象一樣!

反射方法表

這裡有一些常見反射方法的便捷表格:

方法 描述
Type.GetType() 獲取指定名稱的類型
Object.GetType() 獲取當前實例的類型
Type.GetMethods() 返回當前類型的所有公共方法
Type.GetProperties() 返回當前類型的所有公共屬性
Type.GetFields() 返回當前類型的所有公共字段
Type.GetConstructors() 返回當前類型的所有公共構造函數
Activator.CreateInstance() 創建類型的實例
MethodInfo.Invoke() 調用方法
PropertyInfo.GetValue() 獲取屬性值
PropertyInfo.SetValue() 設定屬性值

結論

我們今天涵蓋了很多內容。反射可能一開始看起來有點讓人困惑,但它是在您的 C# 工具包中非常強大的工具。它讓您的程序可以更加靈活和動態,能夠在運行時適應各種條件。

記住,能力越強,責任越大。反射可能比直接代碼慢,並且如果不小心使用,可能會破壞類型安全。但當恰當使用時,它可以解決那些困難或不可能解決的問題。

繼續練習,持續探索,在您知道之前,您將會像專家一樣進行反射!未來的 C# 大師,快樂編程!

Credits: Image by storyset