标签:param har 笔记 over 序列化 exception get 元数据 组合
net高级技术
一、多项目开发
1,添加对项目的引用
//新建一个类库,用来放公共的要使用的类,使用的时候别的项目去引用它
//using 类库文件;
注意事项:注意被引用的类要使用public修饰
被引用的程序集中的类的修饰符,如果不写的话,默认是internal。
效果是,只有当前程序集(类库)内部才能访问。
2,多项目时候的配置文件的读取问题
a,只有主项目的配置文件才起作用(当前启动的)
b,config文件不能改名,不能建多个config,在config里面也不能建多个AppSettings段
3,在项目中“转到定义”,是看不到源代码的,可以使用反编译工具查看
4,调用第三方dll(类库文件)的方法
a,自己的项目就使用项目之间的引用方法
b,使用别人写好的dll就用:添加引用-浏览-选择要添加的dll文件
二、索引器 indexer
1,索引器:没有名字,索引器的内部本质
2,可以是只读或者只写
3,为什么字符串只能char ch = s[5];不能s[5] = ‘a‘
字符串的不可变性;
只读索引
public char this[int index]{get;}
三、密闭类和静态类
1,密闭类 sealed
不能有子类。适用于系统中的基本类,比如String类。可以new对象
2,静态类 声明为 static
没法创建对象,没法New; 无法创建子类,只能声明static成员(方法或者变量)
适用于工具类,不需要new,直接调用它的静态方法或者属性
3,扩展方法
使用方法:
声明一个静态类,增加一个静态方法,第一个参数是被扩展类型,标记为this,
然后在其它类中可以直接调用,也可以使用普通静态方法的方式调用,所以不能访问private和protected成员。
四、深拷贝、浅拷贝
1,引用类型对象变量赋值的时候指向同一个对象
2,可以通过自定义一个拷贝方法赋值出来一个新的对象
3,如果对象之间有引用关系,如果拷贝的时候共享被引用的对象就是浅拷贝,如果被引用的对象也拷贝一份出来就是深拷贝
拷贝一个对象的引用,叫浅拷贝。
如果被引用的对象也拷被拷贝了,叫深拷贝
五、结构体 struct
是值类型,拷贝副本,不能继承,一个结构不能从另一个结构或者类继承。但是,结构从基类Object继承
struct Person
{
public int Age{get;set;}
public String Name{get;set;}
}
六、值类型和引用类型
两者之间的区别:
引用类型变量的赋值只复制对象的引用;引用类型在堆内存(malloc);
值类型变量赋值会拷贝一个副本;值类型在栈内存;
值类型一定是sealed;
七、CTS,CLS,CLR,垃圾回收GC
通用类型系统CTS,Common Type System
通用语言规范CLS,Common Language Specification
公共语言运行时CLR,Common Language Runtime
垃圾回收 GC, Garbage Collection
1,.Net平台下不只有C#语言,还有VB.Net、F#等语言。IL是程序最终编译的可以执行的二进制代码(托管代码)
不同的语言最终都编译成标准的IL(中间语言,MSIL);这样C#就可以调用VB.Net写的程序集(Assembly,dll、exe)
在.Net平台下:不同语言之间可以互联互通、互相调用
2,不同语言中的数据类型各不相同,比如整数类型在VB.Net中是Integer、C#中是int。
.Net平台规定了通用数据类型(CTS,Common Type System),各个语言编译器把自己语言的类型翻译成CTS中的类型。
int是C#中的类型,Int32是CTS中的类型;int是C#中的关键字,但Int32不是
3,不同语言的语法不一样,比如定义一个类A继承自B的C#语法是class A:B{},VB.Net的语法是Class A Inherits B。
.Net平台规定了通用语言规范(CLS, Common Language Specification )
4, IL代码由公共语言运行时(CLR, Common Language Runtime )驱动运行,
CLR提供了垃圾回收
(GC, Garbage Collection,没有任何引用的对象可以被自动回收,分析什么时候可以被回收)、JIT(即时编译器);
5,值类型是放在“栈内存”中,引用类型放到“堆内存”,栈内存会在方法结束后自动释放,“堆内存”则需要GC来回收
八、装箱和拆箱
值类型赋值给Object类型变量的时候,会发生装箱:包装成Object
Object类型变量赋值给值类型的时候会发生拆箱,需要做显示转换。
int i = 10;//值类型赋值
object obj = i;//装箱,不需要进行显示转换,属于隐式转换
int j = obj;//这里报错,发生拆箱,需要进行显示转换 //int j = (int)obj;
注意:在拆箱的时候一定要显示转换回装箱时候的数据类型,否则会报错!!
九、比较相等的问题
1,查看两个对象是否是同一个对象:对象1.RefrenceEquals(对象2);
2,String对象的==方法只是比较内容!
3,Object的Equals方法也比较两个变量指向的是否是同一个对象;对象如果override了Equals方法,就可以进行内容的相同比较
4,默认情况下==不是调用Equals方法,需要重载==运算符
5,String等这些类是重写了Equals方法
十、字符串缓冲池
1,因为字符串的不可变性,字符串一旦被声明,就会一直存在,直到GC判断为未使用对象,被回收
2,字符串是引用类型,程序中会存在大量的字符串对象,会浪费内存、导致性能低下,
因此CLR提供了“字符串缓冲池”,如果发现同样内容的字符串对象,再声明时,直接拿来原来的对象
(对字符串对象进行了重用)
string s1 = "rupeng";
string s2 = "rupeng";
string s3 = "ru" + "peng";
string s4 = new string(s1.ToCharArray());
string s5 = new string(new char[]{‘r‘,‘u‘,‘p‘,‘e‘,‘n‘,‘g‘});
Console.WriteLine(Object.ReferenceEquals(s1,s2));//true,字符串缓冲池的作用,两个字符串引用指向同一个对象
Console.WriteLine(Object.ReferenceEquals(s1, s3));//true,编译器优化,先进行拼接,后进行赋值
Console.WriteLine(Object.ReferenceEquals(s1, s4));//false
Console.WriteLine(Object.ReferenceEquals(s1, s5));//false
Console.WriteLine(Object.ReferenceEquals(s4, s5));//false
十一、ref和out
ref 方法参数的修饰符
1,方法内部修改外部变量的指向;
2,变量传入前必须被赋值;
3,在方法中不是必须被赋值;
out 方法参数的修饰符
1,方法需要多个返回值的时候使用
2,变量传入前不用被赋值,赋值也没用
3,在方法中必须对参数进行赋值
十二、委托
1,委托是一种数据类型,指向一个方法;委托是引用类型,变量可以是null
2,声明委托的方式:
delegate 返回值类型 委托名(参数1,参数2,。。。);比如:delegate void MyDel(int n)
注意:这里除了前面的delegate,剩下部分和声明一个函数一样,但是MyDel不是函数名,而是委托类型名
3,可以声明一个变量,指向和它类型相容的方法
4,如何创建委托类型的对象:
MyDel sp = new MyDel(SayHello);
注意:
SayHello需要和MyDel的参数和返回值一样;
sp这个委托变量就指向SayHello这个方法,不要写成new MyDel(SayHello()),因为加上()就是调用方法了
5,简化的方法:
MyDel sp = SayHello;//编译器会给搞成new MyDel(SayHello)
注意不要写成MyDel sp = SayHello();
6,委托的使用:
委托变量之间是可以互相赋值的,就是一个传递指向方法的过程;
sp()就是调用指向的方法,如果有参数就传递参数
代码示例:
public delegate void MyDel(int n);//第一步,声明一个委托
static void M1(int a)//定义一个方法,方法的参数和返回值要和委托对应
{
Console.WriteLine("M1"+a);
}
MyDel d1 = new MyDel(M1);//声明一个MyDel类型的变量,指向一个指向M1方法的对象
//上面的代码可以简化成 MyDel d1 = M1;
注意:委托是引用类型,可以为null,如果委托变量是null,那么如果调用的话,就会抛出异常:NullReferenceException;
7,Func、Action
.Net中内置两个泛型委托Func和Action(在“对象浏览器”的mscorlib的System下),日常开发中基本不用自定义委托类型了
Func是有返回值的委托,Action是没有返回值的委托
8,匿名方法
使用Delegate的时候很多时候没有必要使用一个普通的方法,因为这个方法只有这个Delegate会用,并且只用一次,这个时候使用匿名方法最合适
匿名方法就是没有名字的方法
示例代码:
MyDelegate p = delegate(int s){s = 10;};
9,lambad表达式
函数式编程,在EntityFramework编程中用的很多
1,Action<int> a1 = delegate (int i){Console.Write(i);};
2, 可以简化为:
Action<int> a2 = (int i)=>{Console.Write(i);};//(=>读作goes to)
3,还可以省略参数类型(编译器会自动根据委托类型推断)
Action<int> a3 = (i)=>{Console.Write(i);};
4,如果只有一个参数还可以省略参数的小括号(多个参数不行)
Action<int> a4 = i=>{Console.Write(i);};
5,如果委托有返回值,并且方法体只有一行代码,这一行代码还是返回值,那么久可以连方法的大括号和return都省略
原本的:Func<int,int,string> f1 = delegate (int i,int j){return "结果是"+(i+j);};
简化为:Func<int,int,string> f2 = (i,j) =>"结果是"+(i+j);
普通匿名类型也是一样用lambda表达式
6,委托深入
集合常用扩展方法:
Where(支持委托)、Select(支持委托)、Max、Min、OrderBy
First(获取第一个,如果没有则异常)
FirstOrDefault(获取第一个,如果一个都没有则返回默认值)
Single(获取唯一一个,如果没有或者多个则异常)
SingleOrDefault(获取唯一一个,如果没有则返回默认值,多个则异常)
ToList、ToArray
7,委托的组合
委托对象可以“+相加”,调用组合后的新委托对象会一次调用被组合取来的委托:MyDel m5 = m1+m2+m3;
组合的委托必须是同一个委托类型
委托的“-”则是从组合委托中把委托移除;
委托如果有返回值,则有一些特殊。委托的组合一般是给事件用的,用普通的委托的时候很少用
8,事件
事件语法:event MyDelegate md1;
加了event关键字实现事件机制的好处:用了event事件,不可以修改事件已经注册的值;不可以冒充进行事件通知了。只能+=、-=
9,委托与事件总结
委托的作用:
占位,在不知道将来要执行的方法的具体代码时,可以先用一个委托变量来代替方法调用(委托的返回值,参数列表要明确)。
在实际调用之前,需要为委托赋值,否则为null
事件的作用:
事件的作用与委托变量一样,只是功能上比委托变量有更多的限制。
比如:
1,只能通过+=或-=来绑定方法(事件处理程序)
2,只能在类内部调用(触发)事件
(面试题)事件和委托的关系:事件由一个私有的委托变量和add_***和remove_***方法组成
事件的非简化写法:声明一个私有的委托变量和add、remove方法
10,委托和事件的区别和关系
错误的说法“事件是一种特殊的委托”
委托用的比较多,事件只有开发WinForm、WPF的时候用的才比较多
事件、索引器、属性本质上都是方法。
(面试题)接口中可以定义什么?
接口中只可以定义方法。接口中可以定义“事件、索引器、属性”,因为他们本质上也都是方法。
十三、反射
1,反射的作用:动态创建对象、动态赋值、动态调用方法
2,反射简介
1,.Net中的类都被编译成IL,反射就可以在运行时获得类的信息(有哪些方法、字段、构造函数、父类是什么等等),
还可以动态创建对象、调用成员
2,每个类对应一个Type对象,每个方法对应一个MethodInfo对象,每个属性对应一个PropertyInfo……。
这些就是类、方法、属性的“元数据”(meta data)。
对象和这个类的对象没有直接关系。
这些“元数据对象”和成员有关,和对象无关,也就是每个成员对应一个对象。
3,类元数据Type
1,使用写好的Person类
1,获取类信息对象Type的方法:
从对象获取:Type type = person.getType();
从类名获取:Type type =typeof(Person); (type 是关键字,不是方法)
从全类名(命名空间+类名)获取:Type type = Type.GetType("com.rupeng.Person");
2,为什么要有这么多获取方式?
主要根据要查询的内容一样,方式也就不一样。
如果有一个对象,就用getType()。
如果没有对象就可以用typeof;
如果要运行时通过配置文件等拿到的字符串来获取就要用Type.GetType("com.rupeng.Person");
3,Activator.CreateInstance(type)
//使用无参数构造方法创建此类的对象(如果没有无参构造函数会报异常)。
要求类必须有无参构造函数。 相当于new Person() 是闲的蛋疼吗?
2,父类中GetType()返回的是什么?this代表“当前对象”,不是“当前类”
3,Type的成员方法
1,IsInterface、IsArray、IsPrimitive、 IsEnum:是否接口、数组、原始类型、枚举等。
2,String Name得到类名(不包含命名空间);String FullName包含命名空间
3,BaseType得到父类的Type。
4,Type的成员
1,构造函数
ConstructorInfo GetConstructor(Type[] types)//获取参数类型匹配的构造函数
ConstructorInfo[] GetConstructors()//获得所有的public构造函数,包括父类的
调用object Invoke(object[] parameters)可以调用构造函数
2,方法
MethodInfo GetMethod(string name, Type[] types)
MethodInfo[] GetMethods() //获得所有的public方法
调用object Invoke(object obj, object[] parameters)可以调用方法
3,属性
PropertyInfo GetProperty(string name) 获取某个属性
PropertyInfo[] GetProperties() 获取所有属性
PropertyInfo的主要成员:
CanRead、 CanWrite是否可读写; GetValue、 SetValue读写值(第一个参数是要在哪个对象要调用)
4,常用的Attribute(特性)
[Obsolete] 表名此成员已过时
当使用PropertyGrid的时候可以修饰属性
[ReadOnly(true)]在编辑器中只读,代码赋值不受影响;
[DisplayName("姓名")] 属性的显示名;
[Browsable(false)]属性是否可见
1,Attribute语法
Attribute用来在代码中附加一些元信息,这些原信息可被编译器,.NetFramework,或者我们的程序使用。
方法、属性、类上都可以标注Attribute
一般起到说明、配置的作用;命名一般以Attribute结尾,如果以Attribute结尾的话使用的时候可以省略Attribute
注解不会直接影响代码的实际逻辑,仅仅起到辅助性作用;如果起作用也是编译器、.NetFramework、程序去解析的
在Type、MethodInfo、PropertyInfo等上都可以调用object[] GetCustomAttributes(Type attributeType,bool inherit)获取标注的注解对象
因为同一个Attribute可能标注多次,所以返回值是数组
十四、正则表达式
1,正则表达式是对字符串进行匹配的语法,用来判断一个字符串是否符合某个规则
2,基本元字符:
a,. 表示除了\n以外的任意的单个字符
b,[0-9]表示的是0-9之间的任意一个整数数字;[a-z]任意一个小写字母;[A-Z]任意一个大写字母
c,\d 表示数字,\D表示非数字,\s表示空白,\S表示非空白,\w表示小写字母或数字和汉字
\W表示特殊符号
d,\ 表示对于 . 等特殊字符转义
e,()提升优先级别和提取组
f,[]代表一个区间中的任意一个:[abc\d]就代表abc或者数字中的任意一个字符
g,| 代表或者
h,+ 是出现1次或者无限次
i,* 是出现0次或者无限次
j,? 是出现0次或者1次
k,{5}出现5次,{1,2}出现一次或者两次,{5,8}出现5次至8次,
{1,}最少出现1次,{3,}最少出现3次
l,^ 以。。开始;$以。。结束
使用Regex.isMatch("目标字符串",@"正则表达式");//返回值是bool类型
提取://使用()进行分组,然后调用match.Groups[0].Value进行取值
Match match = Regex.Match("2016-12-29", @"^(\d{4})\-(\d{1,2})\-(\d{1,2})$");
示例代码:
Console.WriteLine( Regex.IsMatch("2016-12-29", @"^\d{4}\-\d{1,2}\-\d{1,2}$") );
Match match = Regex.Match("2016-12-29", @"^(\d{4})\-(\d{1,2})\-(\d{1,2})$");
if (match.Success)
{
string year = match.Groups[0].Value;
string month = match.Groups[1].Value;
string day = match.Groups[2].Value;
Console.WriteLine("年"+year+"月"+month+"日"+day);
}
else
{
Console.WriteLine("匹配不成功");
}
Console.ReadKey();
十五、对象的序列化
对象序列化是将对象转换成为二进制数据(字节流),反序列化是将其还原为对象。
用处,避免程序重启等情况造成的数据丢失,不仅程序重启、操作系统重启会造成对象的消失,就连退出函数范围等都可能造成对象的消失
序列化和反序列化就是为了保持对象的持久化
注意:一个对象想能序列化,必须标注成[Serializable],其父类和相关的字段、属性都要标记成“可序列化”
序列化只会对类中的字段序列化(只序列化一些状态信息)
类结构改变后,之前序列化的内容尽量不用,否则可能会出错!
使用:
BinaryFormatter类有两个方法:
void Serialize(Stream stream, object pbj)
对象obj序列化到Stream中
object Deserialize(Stream stream)
将对象从stream中反序列化,返回值为反序列化得到的对象
为什么要序列化:
保持对象的持久化,将一个复杂的对象转换流,方便我们的存储与信息交换
应用:
Asp.net中进程外Session要求对象可序列化
还有Xml序列化,应用开发中Json序列化已经代替了二进制序列化和Xml序列化等
十六、XML(可扩展标记语言)
1,XML优点:
容易读懂;格式标准任何语言都内置了XML分析引擎,不用单独进行文件分析引擎的编写
2,是一种格式化的方式来存储数据,可以用记事本、浏览器打开
3,.Net程序中的一些配置文件app.config、web.config文件都是xml文件
4,语法规范:
标签/节点(Tag/Node)、嵌套(Nest)、属性。标签要闭合,属性值要用“”包围,标签可以互相嵌套
XML树,父节点、子节点、兄弟节点(siblings)
xml编写完成以后可以用浏览器来查看,如果写错了浏览器会提示。如果明明没错,浏览器还是提示错误,则可能是文件编码问题。
5,语法特点:
严格区分大小写;
有且只有一个根节点
有开始标签必须有结束标签,除非自闭和(没有内容的时候)<Person/>
属性必须使用双引号
(可写可不写,写了文件类型的时候要注意实际保存的文件类型需要一致)
文档声明:
<?xml version="1.0" encodeing="utf-8"?>
注释:
<!--要注释的内容-->
6,注意编码问题,文本文件实际编码与文档声明中的编码一致
7,读取xml文件:
<Person>
<Student StuID="11">
<StuName>张三</StuName>
</Student>
<Student StuID="22">
<StuName>李四</StuName>
</Student>
</Person>
XmlDocument doc = new XmlDocument();//创建一个读取器对象
doc.Load(@"xml文件的路径");//加载xml文件
XmlNodeList students = doc.DocumentElement.ChildNodes;//拿到xml文件的节点集合
foreach(XmlNode stu int students)
{
XmlElement element = (XmlElement)stu;
string stuId = element.GetAttribute("StuID");
XmlNode nameNode = element.SelectSingleNode("StuName");//获取Person接线的Name
string name = nameNode.innerText;
Console.WriteLine(stuId+","+name);
}
8,生成XML文件
XmlDocument doc = new XmlDocument();//创建XML文件对象
XmlElement ePersons = doc.CreateElement("Persons");//创建根节点对象
doc.AppendChild(ePersons);//将根节点对象添加到XML文件对象
foreach(Person person in ePersons)
{
XmlElement ePerson = doc.CreateElement("Person");
ePerson.SetAttribute("id",person.id.ToString());
XmlElement eName = doc.CreateElement("Name");
eName.InnerText = person.Name;
XmlElement eAge = doc.CreateElement("Age");
eAge.InnerText = person.Age.ToString();
ePerson.AppendChild(eName);//给ePerson添加子节点eName
ePerson.AppendChild(eAge);//给ePerson添加子节点eAge
ePersons.AppendChild(ePerson);//将ePerson添加给根节点
}
doc.Save("文件全路径");
class Person
{
public Person(int id, string name, int age)
{
this.Id = id;
this.Name = name;
this.Age = age;
}
public int Id { set; get; }
public string Name { set; get; }
public int Age { set; get; }
}
Person[] persons = { new Person(1, "rupeng", 8), new Person(2, "baidu", 6) };
标签:param har 笔记 over 序列化 exception get 元数据 组合
原文地址:http://www.cnblogs.com/DotNetStu/p/7396886.html