反射

  • 反射就是运行时,操作某个类型的原数据。
  • 元数据,就是描述数据的数据(创建时间、修改时间等)。
  • 使用 实例.GetType()或typeof(类型)调用。
  • 注意,一个类型只有一个type。
class A{}
...Main(..){
	var a = new A();
	var type1 = typeof(A);
	var type2 = a.GetType();
}

Type能干什么

  1. Type.Name
  2. Type.IsPublic
  3. Type.BaseType
  4. Type.GetInterfaces()
    …以及各种方法

Type案例

class A{
	public string MyProperty{ get; set; }
	public void Function(int a){ Console.WriteLine(a); }
}
...Main(..){
	var a = new A();
	var type1 = typeof(A);

	var a = new A();
	
	var property = type1.GetProperty("MyProperty");
	property.SetValue(a, "aaa", null);
	// 使用SetValue为A类型的a对象的MyProperty属性赋值。
	
	var function = type.GetMthod("Function");
	function.Invoke(a, new object[] { 1 });
	// 使用Invoke调用A类型的a对象的Function方法。
}
  • 反射的意义:也是帮助封闭代码。如果用户想调用属性"MyProperty",在type1.GetProperty()传入该字符串即可。
  • 还可以根据字符串创建类。
  • 配合接口使用,是封闭变化的利器。

根据字符串创建类

Assembly.Load(“程序集名称”).CreateInstance(“命名空间.类名”)

interface MyInterface{
	void A1();
	void B1();
}

public class A : MyInterface{
	public string MyProperty{ get; set; }
	public void Function(int a){ Console.WriteLine(a); }

	public void A1(){}
	public void B1(){}
}

public class B : MyInterface{
	public string MyProperty{ get; set; }
	public void Function(int a){ Console.WriteLine(a); }

	public void A1(){}
	public void B1(){}
}

...Main(..){
	input = Console.ReadLine();
	var instance = (MyInterface)Assembly.Load("CounsoleApplication1").CreateInstance("CounsoleApplication1." + input);
	// 转为接口类(也可以不转)

	input2 = Console.ReadLine();
	var function = instance.GetType().GetMethod(input2);
	function.Invoke(instance, null);
}

特性

  • 特性的用途是提供一个额外的元数据;
  • 比如为了设定某一个属性为必填项,可以在如下案例中使用特性。
class A{
	// []特性修饰属性
	[Required]
	public string MyProperty{ get; set; }
	public void Function(int a){ Console.WriteLine(a); }
}

// 定义一个特性类
public class RequireAttribute : System.Attribute{
	public static bool IsPropertyRequired(object obj){
		var type = obj.GetType();
		var properties = type.GetProperties();

		foreach(var property in properties){
			var attributes = property.GetCustomAttributes(typeof(equireAttribute), false);
			if(attributes.Length > 0){
				if(property.GetValue(obj, null) == null)
					return false;
			}
		}

		return true;
		
	}
}
...Main(..){
	var a = new A(){ };
	if(RequireAttribute.IsPropertyRequired(a))
	{ Console.WriteLine("没有赋值"); } // 没有赋值
	else{ Console.WriteLine("已经赋值"); }
	var b = new A(){ MyProperty = "123" };
	if(RequireAttribute.IsPropertyRequired(b))
	{ Console.WriteLine("没有赋值"); } 
	else{ Console.WriteLine("已经赋值"); } // 已经赋值
}
  • 上述例中,实现了检查一个属性有没有赋值的功能。
  • 很好地封装了代码,为什么这么说?因为只要在一个新属性前加[Required]就可以赋予属性该特性,而不需要修改用于检查的方法。

系统自定义的特性AttributeUsage

class A{
	...;
}

public class RequireAttribute {
	...;
}

[AttributeUsage(AttributeTargets.Property)]
// 意味着特性AttributeTargets只能修饰Property。

...Main(..){
	...;
}

序列化/反序列化

  • 序列化指把一个对象/实例保存成文件等;
  • 序列化后方便在网络上传输。
  • 反序列化为“解码”过程。
// 加一个特性,表示A为可以序列化的。
[Serializable]
class A{
	public string Test = "123";
}

...Main(..){
	var a = new A();
	using(var stream = File.Open(typeof(A).Name + "bin", FileMode.Create)){
		var bf = new BinaryFormatter();
		bf.Serialize(stream, a) // 序列化a, 多了一个文件叫A.bin

	A after = null;
	using(var stream = File.Open(typeof(A).Name + "bin", FileMode.Open)){
		var bf = new BinaryFormatter();
		after = (A)bf.Deserialize(stream);
		// 反序列化A.bin文件
	}
}

  • MSDN说:Stream是所有流的抽象基类,流是字节序列的抽象概念。
  • 例如文件、输入/输出设备、内部进程通信管道或者TCP/IP套接字都为流。
  • 流可以理解为文件传输的方式,具体可以根据流的继承系进行研究学习。

XML

  • XML为数据交换的一个格式,已经约定俗成,被广泛使用;
  • 常见的XML有XML、YAML、JSON…
  • XML是层级结构的,有非常标准的集合元素关系。
<books>
	<book>
		<title>xxx</title>
		<author>yyy</author>
	</book>
	<book>...</book>
</books>

动态编程

  • 涉及到关键字dynamic;
  • 使用动态编程解析XML举例。
string xml = @"
	<books>
		<book></book>
		<book><title>xxx</title></book>
	</books>
	";
dynamic aaa = new DynamicXML(xml);
Console.WriteLine(aaa.book[1].tittle.Value); // xxx 输出时间较长