反射
- 反射就是运行时,操作某个类型的原数据。
- 元数据,就是描述数据的数据(创建时间、修改时间等)。
- 使用 实例.GetType()或typeof(类型)调用。
- 注意,一个类型只有一个type。
class A{}
...Main(..){
var a = new A();
var type1 = typeof(A);
var type2 = a.GetType();
}
Type能干什么
- Type.Name
- Type.IsPublic
- Type.BaseType
- 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 输出时间较长