一、扩展方法:
//1、增加一个静态类
public static class StringExt
{
//2、在静态类中增加一个静态方法,带有this的参数表示当前的IsEmail方法是给string类型扩展的
public static bool IsEmail(this string str)
{
// 扩展方法只是看起来像string中的方法,其实根本不是string类自己的成员,所以在扩展方法中不能访问类中原来的私有成员
return Regex.IsMatch(str,@”^\w+@\w+\.\w+$”);
}
二、XML基础
(一)XML和HTML的区别:
1、 XML有且只有一个根元素
2、 XML中元素必须关闭
3、 XML中元素的属性值必须用引号。
4、 XML大小写敏感(CaseSensitive)
(二)xml文件读写
//1、加载xml文件
XDocument xDoc = xDocument.Load(“x1.xml”);
//循环遍历每个节点
//2、获取根元素
XElement xeRoot = xDoc.Root;
订单案例:
订单号:doc.Root.Element(“OrderNumber”).Value
遍历订单项:
foreach(Xelement element in doc.Root.Descendants(“Items”).Descendants(“OrderItem”))
{
Console.WriteLine(“商品名:{0},数量:{1}”,element.Element(“ItemName”).Value,element.Element(“Count”).Value);
}
读取属性Attribute(“”),读取带属性的订单
foreach(XElement element in doc.Root.Descendants(“Items”).Descendants(“OrderItem”))
{
Console.WriteLine(“商品名:{0},数量:{1}”,element.Attribute(“Name”).Value,element.Attribute(“Count”).Value);
}
三、深拷贝和浅拷贝
无论深拷贝还是浅拷贝都重新创建了对象。
实现方式:
浅拷贝 Object.MemberwiseClone
深拷贝通过二进制序列化实现
四、特性
(一) 特性是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。
1、将应用了特性的程序结构(program construct)叫做目标(target)。
设计用来获取和使用元数据的程序(比如对象浏览器)被叫做特性的消费者(consumer)。
.NET预定义了很多特性,我们也可以声明自定义特性。
2、我们在源代码中将特性应用于程序结构。
编译器获取源代码并且从特性产生元数据,然后把元数据放到程序集中。
消费者程序可以获取特性的元数据以及程序中其他组件的元数据。注意:编译器同时有生产和消费的特性。
3、大多数特性只针对直接跟随在一个或多个特性片段后的结构。
应用了特性的结构称作被特性装饰(decorated或adorned,两者没有什么区别)。
(二)预定义的保留的特性
1、Obsolete特性
Obsolete特性允许我们将程序结构标注为过期的并且在代码编译时显示有用的警告消息。例:
class Program
{
[Obsolete(“Use method SuperPrintOut”)] //将特性应用到方法
static void PrintOut(string str)
{
Console.WriteLine(str);
}
static void Main(string[] args)
{
Printout(“Start of Main”); // 调用obsolete方法
}
}
正常输出:Start of Main
但编译器产生CS0618警告通知我们在使用一个过期的结构:
‘AttrObs.Program.PrintOut(string)’ is obsolete:’Use method SuperPrintOut
另一个Obsolete特性的重载接受了bool类型的第二个参数。这个参数指定目标是否应该被标记为错误而不仅是警告:
[Obsolete(“Use method SuperPrintOut” ,true)]
2、Conditional特性
Conditional特性允许我们包括或排斥某个特定方法的所有调用。例:
[Conditional(“DoTrace”)]
static void TraceMessage(string str)
{
Console.WriteLine(str);
}
当编译器编译这段代码时,会检查是否有一个编译符号被定义为DoTrace(即#define DoTrace)。如果DoTrace被定义,编译器就会像往常一样包含所有对TraceMessage方法的调用。如果没有,编译器就不会输出任何对TraceMessage的调用代码。
(三)其他预定义的特性
CLSCompliant 声明公共暴露的成员应该被编译器检测是否符合CLS。兼容的程序集可以被任何.NET-兼容语言使用。
Serializable 声明结构可以被序列化
NonSerialized 声明结构不能被序列化
DLLImport 声明是非托管代码实现的
WebMethod 声明方法应该被作为XML Web服务的一部分暴露
AttributeUsage 声明特性能应用到什么类型的程序结构。将这个特性应用到特性声明上
(四)自定义特性
1、特性只是某个特殊类型的类。所有特性都派生自System.Attribute。
声明一个自定义特性,做如下工作:
声明一个派生自System.Attribute的类
给它起一个以后缀Attribute结尾的名字
为了安全,通常建议声明一个sealed的特性类。例:
public sealed class MyAttributeAttribute:System.Attribute
{
…
由于特性持有目标的信息,所有特性类的公共成员只能是:
字段、属性、构造函数
2、特性构造函数
(1)特性和其他类一样,都有构造函数。每一个特性至少必须有一个公共构造函数。
在应用特性时,构造函数的实参必须是在编译期能确定值的常量表达式。
(2)比较普通类构造函数的使用和特性的构造函数的使用:
命令语句(普通类):MyClass mc = new MyClass(“Hello”,15);
声明语句(特性):[MyAttribute(“Holds a value”)]
命令语句的实际意义是:“在这里创建新的类”。
声明语句的意义是:“这个特性和这个目标相关联,如果需要构造特性,使用这个构造函数”。
(3)构造函数中的位置参数和命名参数
位置参数:编译器根据参数列表中的参数的位置知道哪个实参和哪个形参相匹配,这种参数叫位置参数。
命名参数:用来设置特性的字段或属性的值,由字段或属性名后接等号和初始化值构成。命名参数是实参。
如下代码显示了使用一个位置参数和两个命名参数来应用一个特性:
3、限制特性的使用
AttributeUsage特性可以用来限制特性使用在某个目标类型上。
例:如果我们希望自定义特性MyAttribute只能应用到方法上,可以这样写:
[AttributeUsage(AttributeTarget.Method)]
public sealed class MyAttributeAttribute:System.Attribute
{ …
五、自己动手写XML序列化器(XML、反射、特性的综合特性)
(一)需求:将Person对象的Age、Name、Email属性序列化为XML文件
(二)调用预定义XML序列化函数完成任务
XmlSerializer xmlSer = new XmlSerializer(typeof(Person));//创建XmlSerializer对象
using(FileStream fs = File.OpenWrite(“person.xml”))
{
xmlSer.Serialize(fs,p);//调用Serialize方法
}
(三)自己动手写XmlSerializer的Serialize方法
1、要写xml的根节点,根节点是类型的名
将方法命名为DoXmlSerialize(string path,object obj),第一个参数是xml文件的路径,第二个参数是需要Serialize的对象;
obj.GetType()取得对象类型,obj.GetType().Name取得类型名;
新建Xdocument对象,将以类型名命名的XElement对象添加为Xdocument的Root(根节点)。
2、创建这个类型的每个属性的xml节点
PropertyInfo[] pinfos = typeObj.GetProperties();
foreach每个属性获取其CannotSerializable特性,如果有就不能被序列化。
object[] objAttrs = property.GetCustomAttributes(typeof(CanNotSerializableAttribute), false);
对于每个属性都要创建一个xml元素
XElement xElement = new XElement(property.Name, property.GetValue(obj, null));
3、创建CanNotSerializable:Attribute特性,标记不能序列化的属性。