C#高级编程特性:反射、特性、序列化与动态编程

一、反射(Reflection)

原理与用途

反射是指程序在运行时能够检查和操作自身结构的能力。通过反射,我们可以:

  • 动态创建类型的实例
  • 访问类型的成员(属性、方法、字段等)
  • 调用类型的方法
  • 获取和设置属性值

示例

interface IMyInterface
    {
        void MethodTestA();
        void MethodTestB();
    }
    class A : IMyInterface
    {
        public void MethodTestA()
        {
            Console.WriteLine("I'm A.MethodTestA");
        }

        public void MethodTestB()
        {
            Console.WriteLine("I'm A.MethodTestB");
        }
    }
class B : IMyInterface
{
    public void MethodTestA()
    {
        Console.WriteLine("I'm B.MethodTestA");
    }

    public void MethodTestB()
    {
        Console.WriteLine("I'm B.MethodTestB");
    }
}
// 反射示例
Console.WriteLine("请输入类名:");
string className = Console.ReadLine();
Console.WriteLine("请输入方法名:");
string methodName = Console.ReadLine();
AssemblyName namespaceStr = Assembly.GetExecutingAssembly().GetName();
object aORb = Assembly.Load(namespaceStr).CreateInstance(namespaceStr.Name + $".{className}");
MethodInfo methodInfo = aORb.GetType().GetMethod(methodName);
methodInfo.Invoke(aORb, null);

这段代码展示了反射的核心应用:

  1. 获取当前执行的程序集
  2. 根据用户输入的类名动态创建实例
  3. 根据用户输入的方法名获取方法信息
  4. 调用该方法
    image

二、特性(Attribute)

原理与用途

特性是一种特殊的类,用于为代码元素(如类型、方法、属性等)添加元数据。特性可以:

  • 提供额外的元数据信息
  • 控制程序的行为
  • 实现声明式编程

代码示例分析

// 自定义Required特性
[AttributeUsage(AttributeTargets.Property)] // 设置该特性只能修饰属性
class RequiredAttribute : Attribute
{
    /// <summary>
    /// 利用反射判断 Required特性标记的属性是否为空
    /// </summary>
    /// <param name="obj"></param>
    /// <returns>null为false否则true</returns>
    public static bool IsPropertyRequired(object obj)
    {
        Type type = obj.GetType(); // 获取obj 的Type
        PropertyInfo[] properties = type.GetProperties(); // 获取obj的所有属性
        foreach (PropertyInfo property in properties) // 遍历所有属性,查找是否包含被Required标记的属性
        {
            object[] attribute = property.GetCustomAttributes(typeof(RequiredAttribute), false);
            if(attribute.Length > 0)
            {
                if (property.GetValue(obj, null) == null) // 假如该标记属性为空则返回false
                    return false;
            }
        }
        return true;
    }
}
// 使用特性
class A : IMyInterface
{
    [Required]
    public string Property { get; set; }
    // ...
}
 A a1 = new A { Property = "" };
 if (RequiredAttribute.IsPropertyRequired(a1))
 {
     Console.WriteLine("a1已赋值");
 }
 else
 {
     Console.WriteLine("a1未赋值");
 }
 A a2 = new A ();
 if (RequiredAttribute.IsPropertyRequired(a2))
 {
     Console.WriteLine("a2已赋值");
 }
 else
 {
     Console.WriteLine("a2未赋值");
 }

这段代码展示了:

  1. 如何定义自定义特性RequiredAttribute
  2. 如何限制特性的应用范围(仅属性)
  3. 如何使用反射检查特性标记的属性
  4. 如何在属性上应用特性
    image

三、序列化(Serialization)

原理与用途

序列化是将对象转换为可存储或传输的格式的过程,反序列化则是其逆过程。序列化可以:

  • 持久化对象状态
  • 在网络上传输对象
  • 在不同应用域之间传递对象

代码示例分析

[Serializable]//可序列化特性
class A : IMyInterface
{
   ...
// 序列化示例(注释部分)
A a = new A();
using (Stream stream = File.Open(typeof(A).Name + ".Bin", FileMode.OpenOrCreate))
{
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(stream, a);
}
Console.WriteLine("序列化完成");
using (Stream stream = File.Open(typeof(A).Name + ".Bin", FileMode.Open))
{
    BinaryFormatter bf = new BinaryFormatter();
    object o = bf.Deserialize(stream);
    Console.WriteLine("反序列化完成");
    o.GetType().GetMethod("MethodTestA").Invoke(o, null);
}

这段代码展示了:

  1. 使用BinaryFormatter进行二进制序列化
  2. 将对象序列化到文件
  3. 从文件反序列化对象
  4. 使用反射调用反序列化对象的方法

序列化类型

  • 二进制序列化:如示例所示,使用BinaryFormatter
  • XML序列化:使用XmlSerializer
  • JSON序列化:使用JsonSerializer(.NET Core)或第三方库如Newtonsoft.Json

四、动态编程(Dynamic Programming)

原理与用途

动态编程允许在运行时动态处理对象,而不需要在编译时知道其类型。通过dynamic关键字,我们可以:

  • 调用未知类型的方法和属性
  • 简化与COM对象和动态语言的交互
  • 实现更灵活的代码结构

代码示例分析

// 动态解析Xml(注释部分)
string xml = @"
        <books>
            <book></book>
            <book><title>123</title></book>
        </books>";
dynamic aaa = new DynamicXml(xml);
Console.WriteLine(aaa.book[1].title.Value);

这段代码展示了:

  1. 使用dynamic类型创建DynamicXml实例
  2. 动态访问XML元素和属性,无需编译时类型信息
posted @ 2026-03-27 18:22  (*_^)?  阅读(3)  评论(0)    收藏  举报