首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

C# 反射機制深度解析:從入門到實戰

     編輯:Java 相關知識

前言

本文旨在系統講解 C# 反射技術,涵蓋類型檢視、成員存取、動態調用等核心內容。筆者因專案需求且網上缺乏優質教程,特整理此文,助開發者快速掌握。

環境準備

VS2012,.NET 4.0,建立控制台應用 ReflectionStudy。在 Program.cs 中定義測試類 RefClass:

public class RefClass
{
    private int _test3;
    private int _test1 { get; set; }
    protected int Test2 { get; set; }
    public int Test3 { get; set; }

    public void Show() { }

    private static void Show2() { }
    public static string Show3(string s) { int b; int c; return s; }
    public string Show(string s) { string a; return s; }
}

一、宏觀檢視:獲取所有成員

1. 僅獲取公共成員

Type t = typeof(RefClass);
MemberInfo[] minfos = t.GetMembers();
foreach (var minfo in minfos)
    Console.WriteLine(minfo.Name);

輸出包含自身公共成員及繼承自 Object 的公共成員(如 ToString、GetHashCode 等)。注意:GetMembers() 預設只返回公共成員,不包含私有/受保護成員。

2. 獲取所有成員(含非公共、實例、靜態)

MemberInfo[] minfos = t.GetMembers(
    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);

此時可見私有字段 _test3、_test1、受保護屬性 Test2、公共屬性 Test3、方法 Show、Show2、Show3 等。

3. 僅獲取當前類聲明的成員(排除繼承)

MemberInfo[] minfos = t.GetMembers(
    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);

加上 BindingFlags.DeclaredOnly 後,輸出僅包含 RefClass 直接聲明的成員。

4. 區分成員類型(字段、屬性、方法)

Func<MemberTypes, string> getType = (x) => {
    switch (x) {
        case MemberTypes.Field: return "字段";
        case MemberTypes.Method: return "方法";
        case MemberTypes.Property: return "屬性";
        default: return "未知";
    }
};
foreach (var minfo in minfos)
    Console.WriteLine($"{minfo.Name}; 類型:{getType(minfo.MemberType)}");

二、深度剖析:字段

1. 獲取字段信息

FieldInfo[] finfos = t.GetFields(
    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (var finfo in finfos)
    Console.WriteLine($"字段名:{finfo.Name}  字段類型:{finfo.FieldType}");

2. 讀取字段值(突破封裝)

RefClass rc = new RefClass { Test3 = 3 };
foreach (var finfo in finfos)
    Console.WriteLine($"字段名:{finfo.Name}  值:{finfo.GetValue(rc)}");

即使是私有字段 _test3、_test1、受保護字段 Test2,反射也能讀取其值。

3. 修改字段值

foreach (var finfo in finfos) {
    finfo.SetValue(rc, 100);
    Console.WriteLine($"字段名:{finfo.Name}  新值:{finfo.GetValue(rc)}");
}

所有字段值均被修改為 100,展現反射的強大與危險性。

三、深度剖析:屬性

屬性本質是 get/set 方法,需先獲取 PropertyInfo,再取得對應的 MethodInfo 進行調用。

PropertyInfo[] pinfos = t.GetProperties(
    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (var pinfo in pinfos) {
    MethodInfo getMethod = pinfo.GetGetMethod(true);  // true 表示包含非公共
    MethodInfo setMethod = pinfo.GetSetMethod(true);
    Console.WriteLine($"Get方法:{getMethod.Name} 返回類型:{getMethod.ReturnType}");
    Console.WriteLine($"Set方法:{setMethod.Name} 參數數:{setMethod.GetParameters().Length}");

    // 調用 set 並讀取
    setMethod.Invoke(rc, new object[] { 123 });
    object val = getMethod.Invoke(rc, null);
    Console.WriteLine($"屬性:{pinfo.Name} 值:{val}");
}

四、深度剖析:方法

MethodInfo[] minfos = t.GetMethods(
    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach (var minfo in minfos) {
    var pars = minfo.GetParameters();
    if (pars.Length > 0 && pars[0].ParameterType == typeof(string)) {
        object result = minfo.Invoke(rc, new object[] { "123" });
        MethodBody body = minfo.GetMethodBody();
        Console.WriteLine($"方法:{minfo.Name} 返回:{minfo.ReturnType} 參數:{pars[0].ParameterType} 名:{pars[0].Name} 結果:{result}");
        Console.WriteLine($"  IL碼長度:{body.GetILAsByteArray().Length} 區域變量數:{body.LocalVariables.Count}");
    } else {
        Console.WriteLine($"無參方法:{minfo.Name} 返回:{minfo.ReturnType}");
    }
}

輸出包含 Show、Show2、Show3 及屬性的 get_/set_ 方法,驗證了屬性本質是方法。

五、總結

反射讓我們在運行時動態探查、操作類型結構,是框架開發、序列化、依賴注入等技術的基石。掌握 BindingFlags 組合、MemberInfo 族類(FieldInfo/PropertyInfo/MethodInfo)的用法,即可應對絕大多數反射場景。實際開發中請謹慎使用,注意性能與安全性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved