闲着没事就把以前学习时的笔记拿出来整理了一下,个人感觉有点用,就想拿出来跟园友共享一下。有些基础性的内容比如基本概念、语法什么的就不发了。

内容:1、构造方法(函数) 2、继承   3、访问修饰符  4、静态和非静态  5、隐藏基类方法  6、重写基类方法  7、抽象方法  8、接口  9、多态和接口  10、值类型与引用类型  11、ref和out  12、类型转换  13、异常处理  14、string字符串处理  15、string常用方法  16、StringBulider  17、File类读取文件  18、文本高亮 19、泛型集合List<T>和Dictionary<TKey,TValue>  20、装箱和拆箱  21、读写数据(Ststem.IO)  22、文件流(FileStream)  23、StreamReader和StringWriter  24、File和Directory  25、序列化  26、Directory类的静态方法  27、正则表达式  28、Regex类  29、字符串提取  30、贪婪模式  31、字符串替换  32、byte数组和字符串的转换  33、委托  34、多播委托  35、事件  36、委托和事件的区别  37、var类型  38、扩展方法  39、XML

1、构造方法(函数):在对象创建的时候初始化字段

public 类名([参数])

{

//执行内容,如this.name=name;(有参数)

}

构造方法没有返回值,void也不写

创建对象时如果没写构造方法系统默认有一个无参的构造方法,一旦用户添加了构造方法,原来默认的无参的构造方法就没有了

默认初始值为:int:0;  bool:false;  string:null;   char:‘\0’;

构造方法的作用:初始化字段(实例化类的时候传入初始值)

调用构造方法:

1)除了new对象的时候,不能直接使用构造方法名调用构造方法

2)this调用构造方法(难点)(一个构造方法调用另一个构造方法)

为了解决代码的重用才使用this调用构造方法

当一个类中出现多个构造方法重载的时候,同时构造方法都需要为字段赋初值

使用this代表当前类的构造方法来使用,根据this后面的参数决定使用哪一个重载

public 构造方法名():this([参数])

{

//代码

}

如:

public Person(string name, int age, string sex)

{

this.name = name;

this.age = age;

this.sex = sex;

}

public Person(string name)

: this(name, 0, null)

{

}

2、继承:

多个类都有共同的字段、属性或方法时,可以使用继承

需要写一个学生类、一个老师类、一个校长类

事先写一个Person类,在写其他类的时候继承这个类,Person叫父类,继承他的叫子类

特征:子类既有父类的非私有字段、属性和方法,又有子类独有的字段、属性和方法

一个子类只能有一个父类,一个父类可以有若干个子类

[访问修饰符] class 子类名:父类名

子类调用父类构造方法的问题(难点)

->构造方法的执行顺序:先父类再子类

->关于构造方法的重载:如果不声明调用哪个构造方法默认执行无参的构造方法

避免错误的方法:

->为父类提供无参构造方法

->在子类中指定调用父类有参的构造方法

注意:父类除构造函数(方法)之外的非私有成员都可以被子类所继承,构造方法不可以被继承,但可以被调用,调用方法: [访问修饰符] 构造方法名([参数]):base(父类构造方法的参数)

public Teacher():base("狗蛋”,20,"女")

{        }    //直接赋值,实例化对象时不需再赋值

public Teacher(string name, int age, string sex)

: base(name, age, sex)

{

this.className = "C#";//老师类独有的字段

}   //继承传递参数,实例化对象时需要赋值

base关键字用于显示声明要调用父类的哪个构造方法,是调用,不是声明不是继承

注意:为避免继承父类时因为构造方法出错,应该为每个声明的类都手动添加一个无参的构造方法

3、访问修饰符

public 最公开的,所有地方都可以访问

private 最隐蔽的,只有本类可以访问

protected 可以在当前类和子类中被访问

internal 只能在本项目中被访问

C#中规定类的访问修饰符只能是public 和internal

类中成员的访问修饰符除以上四种以外还有个(protected internal)即可以在当前类、子类和本项目中被访问

4、静态和非静态

静态使用static标记

静态成员

->如何定义静态成员

在成员前加static关键字

->如何使用静态成员

静态成员不能由实例对象调用,只能用类名调用

使用静态成员,不需要实例化对象

静态成员会在整个应用程序退出时才释放资源,所以这个变量可以在整个程序中共享数据,可用于窗体间传递参数

注意:静态变量过多会占用系统内存,因此声明静态变量时要多加考虑

Main方法是静态的,所以它只能调用静态的方法或参数,若想调用非静态方法,必须new一个类的实例,用实例名调用。

静态类

1)什么情况下要将一个类标记为静态类?

一般情况是,当这个类是一个工具类,里面都是方法,为了让用户调用的时候方便,不需要实例化对象,这时可以将该类标记为static类,此时该类中只能包含静态成员,不能包含实例成员,比如Convert、Console、Read、ReadInt等

2)什么情况下需要在一个普通类中编写一个静态成员,而这个类不能标记为static?

当这个类需要被实例化的时候,如果这个类中有一个成员是所有对象要共享的数据,这时可以将该类中的这个成员标记为静态的,但是这个类还是一个非静态类

3)静态类不能被实例化,不能被继承

4)由于静态成员会在整个程序退出时才释放资源,所以尽量避免写静态字段或静态属性,最好只写静态方法

5)静态类中可以有静态成员和实例成员,因为其不能被实例化,所以静态类中的实例成员无法被调用,也就没有任何意义了

6)静态类不能被继承,也不能继承自其它类,只能继承自Object类

静态构造函数

1)静态构造方法(或字段)在第一次访问这个类的时候执行,并且只执行一次

->静态构造方法与静态类的生命周期(了解)

静态成员属于该类的所有对象。实例成员只属于当前实例

静态类的生命周期:第一次访问类的时候创建,程序结束时才释放

5、隐藏基(父)类方法(了解,用的不多)

当子类和父类有相同名字的方法时,实例化子类调用该方法为子类内的方法,把子类转换成父类后再调用该方法就是父类内的方法了

为了代码规范化,如要有意隐藏父类的方法,要在子类的同名方法前加new关键字,用于   提醒这里是要隐藏父类方法

//隐藏基类方法

class MyBase

{

public void Func()

{Console.WriteLine("我是父类的方法);}

}

class MySub : MyBase

{

public new void Func() //在方法前用new关键字提醒这里是有意隐藏父类方法

{Console.WriteLine("我是子类的方法);}

}

class Program

{

static void Main(string[] args)

{

MySub ms = new MySub();

ms.Func();

// ((MyBase)ms).Func();

MyBase my = ms;

my.Func();

Console.ReadKey();

}

}

6、重写基(父)类方法(多态的体现)

在父类方法前加virtual(虚方法),表示这个方法可以被重写

在子类方法前加override,表示重写基类方法,子类如果不写override就是隐藏

当子类和父类有相同名字的方法时,实例化父类调用的是父类的方法,将子类赋值给父类后,父类调用的就是子类的方法了

一旦父类的方法在子类中被重写,除了实例化父类调用以外,子类或者子类的子类调用时都是调用的最新的那个子类重写方法

此时base和this就有区别了:

如果子类和父类中有名字相同的方法,那么base.Func()就代表父类的方法,this.Func()代表当前类的方法

如果不希望子类再重写,需要在子类方法前加sealed

//重写基类方法

class USB

{

public virtual void Usb() //virtual关键字表示父类方法可以被重写′

{Console.WriteLine("我是父类的方法);}

}

class Phone:USB

{

public override void Usb()//override关键字表示这个方法重写父类的方法

{Console.WriteLine("手机");}

}

class Mp3:USB

{

public override void Usb()

{Console.WriteLine("MP3");}

}

class Program:USB

{

static void Main(string[] args)

{

Console.WriteLine("输入数字");

USB usb = new USB();

switch (Console.ReadLine() )

{

case "1":

usb = new Phone();

break;

case "2":

usb = new Mp3();

break;

default:

break;

}

usb.Usb();

Console.ReadKey();

}

}

隐藏看类型,重写只管新

7、抽象方法

方法前加abstract,圆括号后加分号

[public]  abstract  void 方法名(参数);

抽象方法所在的类也必须是抽象的,不能被实例化,类前加abstract

abstract  class  类名

抽象成员必须出现在抽象类中,但抽象类中可以有抽象成员和实例成员

抽象类的抽象方法默认可以且必须被重写,所以需要重写时不需要再写virtual,直接在子类方法中写override关键字即可重用

抽象类的成员:方法、属性、索引、事件

注意:抽象类中的所有抽象方法在子类中必须要被重写,如果子类中不重写,那这个子类也必须声明成抽象类,但此时子类也就不能被实例化了

8、接口

[访问修饰符] interface 接口名(接口一般以I开头,I+行为+able)

{

//接口成员,一定是抽象成员

}

成员的定义:与抽象成员的写法一样(没有关键字),没有执行体(方法体);没有访问修符;

实现:子类“继承”自接口,接口可以看做是子类的“干爹”,补全抽象的方法

调用:和类的使用方法一样,要使用接口中的方法,则将对象赋值给接口变量

多态:和抽象类的实现一样,接口的多继承使得多态的实现变得灵活

子类继承父类,子类实现(继承)接口:class 子类名:父类名,接口名 或class 类名:接口名

个人理解:接口就是把类中的一种特定的功能性方法封装成接口(如开车、飞等),声明类的时候可以继承这个接口,就拥有了这个接口所特有的功能,就可以在类中实现这个功能,那实现后的这个功能就成为了这个类的一个功能性方法。用接口可以实现多继承,一个类可以继承多个接口,也就拥有了多个功能性方法,声明类的时候可以选择性的继承,比如定义老师的时候可以继承说话、吃饭、教课等接口,定义司机的时候又可以继承说话、吃饭、开车等接口

//定义一个接口,表示Driving功能

interface IDrivable

{

void Driving();

}

class Teacher:Person,IDrivable//继承父类和接口

{

public Teacher(string name, int age, string sex):base(name,age,sex)

{//继承父类的构造方法

}

public void Driving()//实现接口的Driving功能

{

Console.WriteLine("我会开车");

}

public override void ShowMe()//重写父类方法

{

Console.WriteLine("我是老师");

}

}

static void Main(string[] args)

{

Teacher tea = new Teacher("张三", 18, "男");

tea.ShowMe();//调用重写后的方法

tea.Driving();//调用实现后的接口方法

Console.ReadKey();

}

9、多态和接口

接口是可以多继承的,多继承同时会引起方法的重名

为避免重名,显示实现接口:

返回值 接口名.方法名(参数)

{

//方法体

}

显示实现接口的这个方法只能由接口变量进行调用

现阶段记住接口使用的语法,然后将接口直接当做抽象类使用(初学阶段)

10、值类型和引用类型

变量可以看做是一个数据

值类型,是一个存储数据的容器,这个数据就是这个类型表示的数据

引用类型,也是一个容器,但是这个容器存储对象的一个引用(地址),真正的数据在另一块内存中,就相当于是一个指向数据的快捷方式

值类型存储在栈里面,引用类型存储在栈和堆里面(堆里存储的是真实数据,栈里面存储的是真实数据在堆里面的内存地址)

值类型和引用类型会涉及到传参和赋值时的不同,要注意区分

委托(delegate)也是引用类型

值类型赋值赋的是真实的值,引用类型赋值赋的是地址

引用类型是一个变量,两个快捷方式,修改一个快捷方式会影响另一个快捷方式;值类型是一个变量和一个复制后的变量,修改一个变量不会影响另一个变量

所有的值类型都继承自System.ValueType类

11、引用传递:ref和out

使用ref或out就可以实现将引用传递过来

定义方法时,在参数类型前加ref或out

调用方法时,在参数前加ref或out

注:定义变量时不需要加ref或out

当一个变量传递给一个方法时,总是复制一份自己的数据,赋值给方法,那么方法中执行的变量就与方法外的那么变量没有关系了,方法内修改变量值,也不会影响方法外的那个变量。有时会要求多个返回操作(方法中的变量有多个在方法外需要使用),此时可以使用ref标记参数,此时在方法中使用的这个变量与方法外的变量就是同一个变量了,相当于可以使用参数实现返回值

out与ref的作用与使用方法相同

out 必须在方法中赋值

ref必须在方法外赋值

12、类型转换

隐式类型转换:兼容类型,小转大

显式类型转换:即强制类型转换  (转换后的类型)要转换的变量

Convert类型转换:系统封装的方法,Convert.ToInt32()、Convert.ToDouble()等

其他转换方法:int.Parse()、int.TryParse()(第一个参数表示待转换的字符串,第二个out(result)参数表示数字转换成功后的变量,如果转换失败,返回false,为out result赋值为0)

用int.TryParse()代替try-catch,释放内存,提高性能

不止int类型有TryParse,所有基本类型都有TryParse,用法都一样

13、异常处理(try-catch、try-catch-finally、try-finally)

Exception是一个专门用来封装异常的一个类型

两个属性:message(异常说明文本)和stackTrace(异常抛出的顺序)

抛出异常:throw Exception的一个对象(new一个对象)

从出现异常的try向上依次抛出(方法之间依次调用),直至处理,找到最近的catch捕获异常(用于try-finally语句,catch块在方法以外,执行顺序是try-finally再向上寻找catch执行异常捕获)

Finally用于释放资源,finally{},程序执行完try-catch后会再执行finally语句块

Finally总会执行,即使try-catch中有return

try

{  }

catch (Exception ex)

{ throw; }

finally

{  }

Try-finally用处不多,用于释放资源

使用异常会降低系统性能,尽量少用

14、string字符串处理

构造函数:string(char[] chs)、string(char ch,int count)

string str = new string(’a‘,’b’,’c’);//abc

string str = new string(‘a’,3);//aaa

3.144.ToString(“0.0”);用于控制格式,会四舍五入

字符串可以当做数组进行处理(使用下标读取,拥有数组的各种属性)

string str = “不可见的你”;  此时str[1]就是“可”了

通过索引得到的数据是char类型,字符串不可改变,使用索引无法修改字符串的数据

要想修改可将字符串变成字符型数组,str.ToCharArray()

string是引用类型

string str = string.Empty;声明一个空字符串

判断字符串是否为空:

str.Length == 0(推荐)

str ==“”

str == string.Empty

String.IsNullOrEmpty(要判断的字符串)(推荐)

15、string常用方法

1)字符串比较:bool isTrue = string.Equals(string a,string b)

String.Equals(str1,str2);

Str1.Equals(str2,StringComparison.OrdinalIgnoreCase); //第二个参数意思是不区分大小写

string.Compare(str1,str2);

Equals方法:

String重载的方法判断两个,一个是==,一个是EqualsHelper

==判断两字符串是否相同

EqualsHelper判断两个字符串中每一个字符是否相同

Object的重载是来自于object类,是继承下来的

在object中使用的是==和Equals方法

Equals方法是一个虚方法,由string重写了,调用的是object.ReferenceEquals方法和EqualsHelper方法

注意:==默认表示判断两个对象的地址是否相同,与object.ReferenceEquals方法一样

String提供的str1.Equals(str2)判断地址是否相同,字符串是否object提供的virtual Eaulse(object)

Equals和==的区别:

Equals会判断两个值的内存地址;==只判断值是否相等。

Compare方法:

int result = String.Compare(str1,str2);

str1>str2 -> 1    str1 == str2 -> 0   str1<str2 -> -1

string.Compare方法比较两个字符串,这两个字符串字母顺序表示大小,按照字典排序规则进行比较(对于char类型:A>a,B>a,b>A同一个字母,大写>小写,不同字母按照字母顺序后面的大于前面的;对于string类型不是按照埃克森码比较,A>a,b>A,B>a)

2)大小写转换:ToLower()和ToUpper()

3)str1 = str1.Trim([params char[] chs]);去除字符串两边的空格,或chs中出现的字符(重载)

str1 = str1.TrimEnd(params char[] chs);去除字符串的末尾chs中出现的字符

str1 = str1.TrimStart(params char[] chs);去除字符串的开头chs中出现的字符

4)合并与分割

合并字符串:string s = string.Join(str1,str2,str3,...)

分割字符串:string[] strArray = str1.Split(‘a’);

string[] strArray= str1.Split(new char[]{‘a’,’b’},StringSplitOptions.RemoveEmptyEntries);去掉a、b和所有空格

5)字符串查找

Contain包含,返回bool类型的值,str1.Contain(“爱”);

IndexOf检索位置,返回字符串中某个字符的位置(int)找不到则返回-1

str.IndexOf(要找的字符或字符串)

str.IndexOf(要找的字符或字符串,开始寻找的位置)

str.LastIndexOf()是从后往前寻找,用法同str.IndexOf()

注意:IndexOf和LastIndexOf中第二个参数(开始寻找的位置)只是为了说明要查找的是字符串中的哪一个字符(如果字符有重复),即按查找顺序在开始位置后的第一个字符,返回的索引依然是该字符在整个字符串中的索引,而不是从查找位置开始的索引。

6)截取子字符串

string s =str1.Substring(开始的位置,子字符串的长度)

String s = str1.Substring(开始的位置)

7)判断字符串的开头和结尾

bool a = str1.StratWith(字符串);

bool a = str1.EndWith(字符串);

8)字符串的插入、移除和替换

插入:string str2 = str1.Insert(位置(int),要插入的人字符串(string));

移除:string str2 = str1.Remove(位置(int),长度(int));

string str2 = str1.Remove(位置(int));移除该位置后的所有字符

替换:string str2 = str1.Replace(旧字符串,新字符串);

9)格式化字符串

String.Format(格式化的字符串,填坑的参数)

string str1 = String.Format(“{0},{1}”,str2,str3);

10)判断字符串是否为空

String.IsNullOrEmpty(str);

10)字符串的方法(总结)

增:添加(+=)、插入(Insert)

删:Remove

改:Replace、 ToUpper、ToLower、Trim、TrimStart、TrimEnd、Split、Join、new String、SubString、Format

查:Contains、IndexOf、LastIndexOf、StartsWith、EndsWith、ToCharArray、Length、Empty

比:Equals、Compare

16、StringBuilder

大量字符串拼接的时候性能非常差,很难完成大型数据的拼接

(Stopwatch对象可以记录程序运行的时间,Start开始计时,Stop结束)

使用StringBuilder:StringBuilder sb = new StringBuilder();

sb.Append(要添加的字符串);//向sb中添加数据

sb.AppendLine(要添加的字符串);//向sb中添加数据后换行,等价于sb.Append(要添加的字符串+”\r\n”);

sb.AppendFormat(要添加的字符串);格式化处理,等价于 sb.Append(string.Format(要添加的字符串));

string str = sb.ToString;输出或赋值时要转换成string

在处理大型数据的时候,StringBuilder要比普通的string处理快很多,因为处理大型数据要用StringBuilder

17、读取文件

string[] lines = File.ReadAllLines(@"H:\传智播客实训资料代码\第9天\a.csv", Encoding.Default);//按行读取

string[] lines = File.ReadAllText(@"H:\传智播客实训资料代码\第9天\a.csv", Encoding.Default);//读取所有文本

string[] lines = File.ReadLines(@"H:\传智播客实训资料代码\第9天\a.csv", Encoding.Default);//读取一行文本

string[] lines = File.ReadAllBytes(@"H:\传智播客实训资料代码\第9天\a.csv", Encoding.Default);//读取字节

18、文本高亮

->让文本框获得焦点--txtContent.Focus();

->找到要高亮的位置--pos

->选中(高亮)的字符串长度--length

->调用TextBox的选中方法txtContent.Select(pos,length)

19、泛型集合   List<T>和Dictionary<TKey,TValue>

List集合:动态的自定义数组

List<类型> 集合名 = new List<类型>();

List用法与ArrayList一样,不同点在于定义时和使用时的类型固定,因此可以完全替代ArrayList

类型[] = list.ToArray()//将List转换成该类型的数组

Dictionary集合:动态的自定义键值对

Dictionary<类型,类型> 集合名 = new Dictionary<类型,类型>();

Dictionary用法与Hashtable一样,不同点在于定义时和使用时的类型固定,因此可以完全替代Hashtable

20、装箱与拆箱

直接将值类型赋值给引用类型就是装箱

将存储值类型的引用类型强制转化为对应的值类型就称为拆箱

Object o = 1;//装箱      int n = (int)o;//拆箱

装箱对值类型保持无关性,装箱对引用类型保持相关性

装箱和拆箱会对性能有一定的影响

21、读写数据(I/O操作、System.IO类)

System.IO.Path类,专门处理字符串路径,是一个静态类

string path = @“D:\window\system\file.txt”;

获取文件名:string fileName = Path.GetFileName(path);

获取后缀名:string fileName = Path.GetExtension(path);

修改后缀名:path = Path.ChangeExtension(待修改的路径,“mp3”);

获取文件夹名:string fileName = Path.GetDirectoryName(path);

合并路径:path= Path.Combine(路径1,路径2,路径3...);

临时文件夹:path = Path.GetTempPath();

绝对路径:从盘符开始的最精确的路径

相对路径:相对于当前文件同一个目录作为参照的路径

相对路径和绝对路径:区分就看有没有根目录盘符的标记

22、文件流(FileStream)

1)引入命名空间

2)创建FileStream对象FIleStream fs = new FileStream(文件名,FileModel,FileAccess)

FileStream fs = new FileStream(@"D:\a.txt", FileMode.Create, FileAccess.Write);

FileModel:对文件的处理方式(打开、创建、追加)

FileAccess:对文件的操作:读、写

3)使用方法操作

写一个字节:fs.WriteByte()

写一个字节片段(将字节数组中的数据写入到fs指定的文件):

fs.Write(存放字节的数组,开始写字节的数组下标,要写的字节数)

读一个字节:fs.ReadByte()

读一个字节片段(将fs指定的文件中的数据读取到字节数组):

fs.Read(存放字节的数组,开始存放字节的数组下标,要读的字节数)

4)释放资源

fs.Close()和fs.Dispose()方法(两个都要调)

23、StreamReader和StreamWriter

StreamReader:专门用来读取文本文件的流

1)引入命名空间:IO

2)new一个FileStream指向文件

3)new一个StreamReader,构造函数参数是FileStream的对象

4)调用方法

StreamReader有一个属性EndOfStream:判断当前的流位置是否在文件流的末端,一般用来判断文件是否读完

StreamWriter:专门用来写入文本文件的流

1)引入命名空间:IO

2)new一个FileStream指向文件

3)new一个StreamWriter,构造函数参数是FileStream的对象

4)调用方法

24、File和Directory对文件和目录操作做了一个封装

增(Create):创建文件或文件夹

删(Delete):删除文件或文件夹

改:改名字 File.Move(“1.txt”,“2.txt”)

查:...

判断是否存在(Exists)

移动文件:File.Move(“1.txt”,“2\1.txt”)

复制文件:Copy

Directory用于处理文件夹(目录)

删除目录的时候如果目录不是空的则会报错,此时需要在Delete内添加一个true

Directory.Delete(“1”,true);

25、序列化:

序列化:把一个对象的内容存储到磁盘上(文件流)、网络上(网络流)、内存里(内存流),下次需要用到对象数据的时候可以直接拿来用

反序列化:把已经序列化存储到磁盘、网络、内存里的对象数据,提取到项目中的对象中

序列化步骤:

1)创建一个文件流

2)为需要序列化的对象添加标记([Serializable]表示此对象可以被序列化)

3)创建BinaryFormatter(导入命名空间)

4)调用Seralize方法(bf.Seralize(文件流对象,需要被序列化的对象))

反序列化步骤:

1)创建一个文件流

2)为需要序列化的对象添加标记([Serializable]表示此对象可以被序列化)

3)创建BinaryFormatter(导入命名空间)

4)调用DeSeralize方法(object ob = bf.DeSeralize(文件流对象))

反序列化定义接收类型的时候必须根据原序列化的程序集确定类型

建议:在使用序列化的时候尽量避免使用自动属性,因为自动属性在每次编译的时候自动生成的字段名可能不一样,所以在反序列化的时候可能会造成问题

注意:如果序列化和反序列化不在同一项目下,那反序列化的时候需要引用原序列化的程序集

26、关于文件夹下的文件与子文件夹

Directory类的静态方法

获取子文件名:string[] s = Directory.GetFiles(@“D:\dir“);

获取特定后缀名的子文件名:string[] s = Directory.GetFiles(@“D:\dir“,”*.txt“);

获取所有文件夹名:string[] s = Directory.GetDirectories(@“D:\dir“);

27、正则表达式

元字符:

1).(点)表示除\n以外任意的单个字符

2)[ ]表示括号内的任意一个字符(如a[xyz]b表示axb或ayb或azb)

3)^在[ ]括号内表示取反(如^[a-z]表示除小写字母以外的所有字符)

4)^匹配一串字符的开始(^abc表示以abc为开头的任意字符串)

5)$匹配一串字符的结尾(abc$表示以abc为结尾的任意字符串)

5)|表示“或”,优先级最低(如a|bc表示a或bc,(a|b)c表示ac或bc)

6)()可以改变优先级、提取组

7)*表示限定前面的字符出现任意次数(abc*表示ab、abc、abcccc......(abc)*表示abc、abcabc)

8)+ 至少出现一次,也可出现多次(xa+y表示xay、xaay...)

9)?表示出现0次或1次

10){n}限定前面的表达式出现n次

11){n,m}至少出现n次,最多出现m次

12){n,}至少出现n次

13)\d表示0-9,\D表示\d的反面

14)\s表示空白符,\S表示\s的反面

15)\w表示数字、字母、下划线、汉字,\W表示\w的反面

注:正则表达式的转义符也是\,如果要表示*(星),可以写成\*,要表示一个\,可以写成\\

28、Regex类

Regex.IsMatch(待判断的字符串,正则表达式)判断一个字符串是否匹配某个正则表达式

!如果正则表达式没有^和$,那默认不设定开头和结束,此时只要待判断的字符串中含有该正则表达式就返回true

^z|food$:表示以z开头的任意字符串或者以food结尾的任意字符串,都返回true

因为|的优先级最低,所以上边的表达式其实是(^z)|(food$)

Regex.Match()从某个字符串中提取匹配某个正则表达式的某个子字符串,但只能提取一个

Regex.Matches()同上,可以提取所有的匹配字符串

Regex.Replace()字符串替换,把所有匹配正则表达式的字符串替换为对应的字符

29、字符串提取

字符串提取的时候一般不加^和$

Match m = Regex.Match(原字符串,要提取的正则表达式)

m.Value属性表示提取到的字符串

m.Group[n]:提取组,按正则表达式中()括号对的个数,m.Group[0]表示整个字符串,m.Group[1]表示第一个括号内的内容,所以提取组的时候要从下标1的地方开始

MatchCollection mc = Regex.Matches(原字符串,要提取的正则表达式)

MatchCollection是一个集合,需要foreach遍历输出(遍历时的类型是Match)

30、贪婪模式

定义:当正则表达式提取的时候,如果一个字符或多个字符都能匹配,这时会按照使用最多字符的方式来匹配。

正则表达式默认采用贪婪模式,尽多的匹配

在限定符后面使用问号用来终止贪婪模式,即只会提取匹配的第一个

string s = “aaaa bbbbbbbb”;string s1 = “[a-zA-Z]+”;  匹配结果:aaaa

string s = “aaaa bbbbbbbb”;string s1 = “[a-zA-Z]+?”;  匹配结果:a

31、字符串替换

String s =Regex.Replace(原字符串,待替换的正则表达式,替换后的字符串);

如:string s = Regex.Replace(s, "-+", "-");//把字符串s中的所有-替换成一个-

提取组替换:

string s = "aaa13812345678bbb";

s = Regex.Replace(s, @"(\d{3})(\d{4})(\d{4})", "$1****$3");//把手机号中间4位替换成4个*

32、byte数组和字符串的转换

byte[] bt= System.Text.Encoding.UTF8.GetBytes(str);

string str = System.Text.Encoding.UTF8.GetString(bt);

33、委托(delegate)

委托是一种数据类型(和类一样),可以将方法赋值给委托对象,可以理解为方法类型

定义(在命名空间下,或添加一个cs文件,和类的定义一样):

1)使用delegate关键字

2)这个委托将来要存储的方法如果没有返回值,那么委托也要定义成void,参数也要与方法保持一致

3)委托是一个数据类型,用的时候需要传递一个变量

4)创建委托对象的时候可以不用new,系统编译时会自动给我们new

定义委托类型:public delegate void ChangeTxtDelegate(string str);

创建委托对象:public ChangeTxtDelegate changeTxt;  //Form1中

给委托赋值:f1.changeTxt = ChangeText;  //Form2中

调用委托:changeTxt(txt);  //Form1中,此种调用方法为简写,实际上是changeTxt.invoke(txt);

创建委托对象时也可直接对其赋值:ChangeTxtDelegate changeTxt = new ChangeTxtDelegate(ChangeText) ;

用法(窗口间传值):委托要声明在需要被传值的对象内,比如Form1要提取Form2中的数据(即Form2往Form1传值),就应该把委托声明在Form1中,在Form2中写一个方法获取要传的数据,并且赋值给Form1的委托,最后在Form1中调用委托就ok了。(委托声明位置不绝对,还需要考虑当前活动窗口的问题,要声明再活动窗口中,有时也可声明在被提取值的窗口内)

作用:可以在某个代码内部,嵌入一段外部代码(外部写一个方法赋值给委托或在定义方法时把委托类型作为参数,调用时把方法名作为参数传递给委托对象,那么委托就执行该方法,不同的外部项目可以写不同的方法赋值给委托,可以实现一个委托选择性执行多种方法的灵活性),相当于是注入

什么情况下使用委托?

当一个类型中需要嵌入一段代码,但是这段代码具有不确定性,是根据使用这个类型的用户来确定代码的,这时就可以在该类型中使用一个委托,保证在某种情况下会调用该委托,用户将对应的方法传递给该委托,就会调用这个方法

可以把静态方法或者私有方法赋值给委托了变量,赋值后只要能使用到该委托变量的地方就能使用该方法,打破了访问修饰符的限制

一般在调用委托前或者触发事件前,都要判断委托变量或事件是否为null,如果为null则不调用

34、多播委托

MyDelegate md = new MyDelegate(M1);  md+=M2;(增加某个方法)md-=M4;(去掉某个方法)

使用委托时,如果不是+=而是直接用=赋值,则会将前面增加的所有方法都覆盖掉

多播委托可以存储多个方法,委托中方法调用的顺序与增加方法时的顺序是一致的,但是,不要依赖于这个顺序(微软没有承诺这样的顺序,万一以后改了就GG了)

多播委托中,如果要是有返回值,只会得到最后一个方法返回的结果。可以通过调用GetInvocationList()方法返回当前委托中的所有方法,返回值类型时一个Delegate数组(委托数组),再用foreach遍历调用所有方法

所有定义的委托都继承自抽象类MulticastDelegate,而MulticastDelegate又继承自Delegate抽象类

多播委托内部是将绑定在当前委托对象上的每个方法,都转换成一个委托对象,并且存储在了一个叫_invocationList的object数组中。当调用委托的时候,其实就是循环遍历_invocationList数组,并且调用其中的每个委托

多播委托中,如果其中的某个方法执行时发生了异常,则后面的方法不再执行。

多播委托中只能存储同一类型的委托,即返回值、参数都相同

35、事件

事件是在特定条件下执行的动作,这个动作是由用户确定的。如Button的Click事件,其动作是由程序员写的,因此可以用委托来实现这个功能,写不同的方法赋值给委托变量。

但用委托模拟方法有两个缺点:

1)定义的委托可以在类外部的任何地方被触发,即非特定条件下也可以调用。因为委托变量是public修饰,改为private就不能在外部赋值了。

2)由于委托可以用=(等号)赋值,所以就有可能把前面已经注册的事件处理程序都覆盖掉。

而用事件就可以解决以上问题:

1)用事件必须先定义一个委托,否则无法使用事件

2)实例化委托变量的时候,在委托类型名前面、访问修饰付的后面加event关键字,就定义了一个事件

3)使用方法与委托一样,只是避免了以上两个问题

4)由于事件只能有+=或-=赋值,所以就避免了用=(等号)赋值时覆盖前面事件处理程序的问题

5)由于事件不能在定义事件的类以外被触发,所以也就避免了冒充事件触发的问题。

36、委托和事件的区别(面试常考)

委托和事件没有可比性,委托是数据类型,事件是委托类型的变量

委托可以用+=、-=、=赋值,可以在类的外部被调用

事件只能用+=、-=赋值,不能在类的外部被调用

事件的内部是用委托实现的

事件的作用和委托变量(不是委托,是委托变量)一样,只是在功能上受到一定的限制

37、var类型

var只能用作局部变量,可以赋任何类型的值。

var a = 1;和int a = 1;两者完全一样

var不能作为类的成员的类型,不能用作参数,不能用作返回值,只能用作局部变量

38、扩展方法(不修改微软系统方法源代码,实现系统方法的增加)

1)添加一个静态类

2)在静态类中增加一个静态方法,方法参数是:(this+要扩展的类名+变量名,该方法的参数)

如要在string类中添加一个验证是否是Email格式的扩展方法:

public static bool IsEmail(this string str)

{

return Regex.IsMatch(str, @"^\w+@\w+\.\w+$");

}

string a = "1321321@qq.com";

Console.WriteLine(a.IsEmail());

扩展方法只是看起来像类中的方法,其实不是,所以在扩展方法中也访问不到类中原来的私有成员

因为会扰乱系统方法,所以不建议使用,尽量不用

39、XML

XML是用一种格式化的方式来存储数据,可以用记事本打开

1)XML有且只有一个根元素

2)有开始标签就必须得有结束标签,且区分大小写

3)元素的属性值要用引号

读取XML文件,通过XDocument(需要添加命名空间)

读取整个XML文件: XDocument xd = XDocument.Load(XML文件路径)

循环遍历每个节点:

1)获取根节点  XElement xeRoot = xd.Root;(xeRoot.ToString()表示XML文档的内容)

2)递归遍历XML中的每个节点

遍历xeRoot下面的所有子节点:

public static void GetEle(XElement xe)

{

foreach (XElement ele in xe.Elements())

{

Console.WriteLine(ele.Name);

GetEle(ele);

}

}

GetEle(xeRoot);

例:读取XML数据

<CFX>

<MSG>

<交易码val="1000" />

<流水号val="100000000000000001" />

<金额val="1234567890.12" />

<付款机构val="1234" />

<付款单位账号val="12345678901234567890" />

<收款机构val="1234" />

<收款单位账号val="12345678901234567890" />

</MSG>

<MSG>

<交易码val="1000" />

<流水号val="100000000000000002" />

<金额val="1234567890.12" />

<付款机构val="1234" />

<付款单位账号val="12345678901234567890" />

<收款机构val="1234" />

<收款单位账号val="12345678901234567890" />

</MSG>

</CFX>

VS中读取XML的数据:

XDocument xd = XDocument.Load("ytbank.xml");  //加载XML文件

XElement xeRoot = xd.Root;  //获取根节点

foreach (XElement item in xeRoot.Elements())  //遍历根节点,获取第一级子节点(MSG)

{

foreach (XElement itema in item.Elements())  //遍历第一级子节点,获取第二级子节点

{

Console.WriteLine("{0}:{1}", item.Element(itema.Name).Name, item.Element(itema.Name).Attribute("val").Value);  //获取节点名和属性值

}

Console.WriteLine("==================================");

}

XML写入:

XDocument xdoc = new XDocument();  //创建一个XML对象

XElement xeleRoot = new XElement("Websites");  //创建一个根节点

xdoc.Add(xeleRoot);  //将根节点添加到XML文件中

xeleRoot.SetElementValue("baidu", "http://www.baidu.com");  //添加一个节点以及内容

XElement xeleGoogle = new XElement("website");  //创建一个节点

xeleGoogle.SetAttributeValue("url", "http://www.google.com");  //添加属性和属性值

xeleGoogle.SetElementValue("name", "谷歌"); //为节点添加子节点

xeleGoogle.SetElementValue("age", "14");

xeleGoogle.SetElementValue("boss", "谢盖尔");

xeleRoot.Add(xeleGoogle); //将节点添加进根节点

xdoc.Save("website.xml");  //保存一个XML文档路径

.NET基础笔记(C#)的更多相关文章

  1. Java基础笔记 – Annotation注解的介绍和使用 自定义注解

    Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 |  被围观 25,969 views+ 1.Anno ...

  2. php代码审计基础笔记

    出处: 九零SEC连接:http://forum.90sec.org/forum.php?mod=viewthread&tid=8059 --------------------------- ...

  3. MYSQL基础笔记(六)- 数据类型一

    数据类型(列类型) 所谓数据烈性,就是对数据进行统一的分类.从系统角度出发时为了能够使用统一的方式进行管理,更好的利用有限的空间. SQL中讲数据类型分成三大类:1.数值类型,2.字符串类型和时间日期 ...

  4. MYSQL基础笔记(五)- 练习作业:站点统计练习

    作业:站点统计 1.将用户的访问信息记录到文件中,独占一行,记录IP地址 <?php //站点统计 header('Content-type:text/html;charset=utf-8'); ...

  5. MYSQL基础笔记(四)-数据基本操作

    数据操作 新增数据:两种方案. 1.方案一,给全表字段插入数据,不需要指定字段列表,要求数据的值出现的顺序必须与表中设计的字段出现的顺序一致.凡是非数值数据,到需要使用引号(建议使用单引号)包裹. i ...

  6. MYSQL基础笔记(三)-表操作基础

    数据表的操作 表与字段是密不可分的. 新增数据表 Create table [if not exists] 表名( 字段名 数据类型, 字段名 数据类型, 字段n 数据类型 --最后一行不需要加逗号 ...

  7. MYSQL基础笔记(二)-SQL基本操作

    SQL基本操作 基本操作:CRUD,增删改查 将SQL的基本操作根据操作对象进行分类: 1.库操作 2.表操作 3.数据操作 库操作: 对数据库的增删改查 新增数据库: 基本语法: Create da ...

  8. MYSQL基础笔记(一)

    关系型数据库概念: 1.什么是关系型数据库? 关系型数据库:是一种建立在关系模型(数学模型)上的数据库 关系模型:一种所谓建立在关系上的模型. 关系模型包含三个方面: 1.数据结构:数据存储的问题,二 ...

  9. JavaScript基础笔记二

    一.函数返回值1.什么是函数返回值    函数的执行结果2. 可以没有return // 没有return或者return后面为空则会返回undefined3.一个函数应该只返回一种类型的值 二.可变 ...

  10. JavaScript基础笔记一

    一.真假判断 真的:true.非零数字.非空字符串.非空对象 假的:false.数字零.空字符串.空对象.undefined 例: if(0){ alert(1) }else{ alert(2) } ...

随机推荐

  1. 纯代码实现CSS圆角

    我这里说的是纯代码,是指的不使用图片实现圆角,图片实现圆角,这里就不说了. 纯代码实现圆角主要有3种方法: 第一种:CSS3圆角   #chaomao{     border-radius:2px 2 ...

  2. word中利用宏替换标点标点全角与半角

    Alt+F11,然后插入-模块: 复制下面代码到编辑窗口: Sub 半角标点符号转换为全角标点符号() '中英互译文档中将中文段落中的英文标点符号替换为中文标点符号 Dim i As Paragrap ...

  3. 如何在Visio 2007中画接口和实现类的关系图

    http://blog.sina.com.cn/s/blog_53fc9db50100as5o.html 在Visio图形元素上,点击右键,选择“形状显示选项”,将“实现链接”选中,这个时候,类图形元 ...

  4. MyBatis 多个查询条件的传递

    <!-- 方法1,构建查询对象: QueryCondition qc = new QueryCondition(); qc.setGender(1); qc.setBirthday(new Da ...

  5. Bootstrap入门(三十)JS插件7:警告框

    Bootstrap入门(三十)JS插件7:警告框 通过这个插件可以为警告信息添加点击以及消失的功能. 当使用一个.close按钮,它必须是第一个子元素.alert-dismissible,并没有文字内 ...

  6. IOS获取经度纬度

    仔细研究了一下SDK文档,再结合网上的方法,写了这一个简单的获取经纬度的方法,大家看看就好. 首先要导入CoreLocation.Frame 包 .h 文件 1 2 3 4 5 6 7 8 9 #im ...

  7. [JQuery]Jquery对象和dom对象

    jquery对象是jquery包装dom对象后产生的对象,它们都只能使用各自的方法. 1.定义变量时,通过$来区分: var $variable = jquery对象: var variable = ...

  8. WebForm 三级联动

    三级联动 数据库根据父级代号条件写查询 返回list<>集合 方法一: 创建三个下拉列表: ※AutoPostBack:否发生自动回传到服务器的操作.如果把该属性设置为 TRUE,则启用自 ...

  9. Salesforce的Auto Number

    在Salesforce中新建Object的时候,可以对Name选择Auto Number,即自动编号.如果没有仔细阅读说明的话,会有一个很容易让人迷惑的地方. 在选择时候,Salesforce提供的示 ...

  10. C++ cout 输出小数点后指定位数

    在C中我们可以使用 printf("%.2lf",a);但在C++中是没有格式操作符的,该如何操作: C++使用setprecision()函数,同时必须包含头文件iomanip, ...