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);
这段代码展示了反射的核心应用:
- 获取当前执行的程序集
- 根据用户输入的类名动态创建实例
- 根据用户输入的方法名获取方法信息
- 调用该方法
![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未赋值");
}
这段代码展示了:
- 如何定义自定义特性
RequiredAttribute - 如何限制特性的应用范围(仅属性)
- 如何使用反射检查特性标记的属性
- 如何在属性上应用特性
![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);
}
这段代码展示了:
- 使用
BinaryFormatter进行二进制序列化 - 将对象序列化到文件
- 从文件反序列化对象
- 使用反射调用反序列化对象的方法
序列化类型
- 二进制序列化:如示例所示,使用
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);
这段代码展示了:
- 使用
dynamic类型创建DynamicXml实例 - 动态访问XML元素和属性,无需编译时类型信息



浙公网安备 33010602011771号