大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > C#技巧 > C#高级技巧总结

C#高级技巧总结

关键词:C#高级  阅读(843) 赞(13)

[摘要]本文主要总结了一些C#高级技巧,也是很有效的开发技巧,与大家分享.

程序集

程序集概念:

程序集是.net中的概念。

.net中的dll与exe文件都是程序集。(exe与dll的区别(exe有程序主入口,可以执行,dll没有主入口,不可运行))

程序集(Assembly),可以看做是一堆相关类打一个包,相当于java中的jar包(*)

程序集的内容:

程序集包含:

类型元数据(描述在代码中定义的每一类型和成员,二进制形式)

程序集元数据(程序集清单、版本号、名称等)

IL代码(这些都被装在exe或dll中)

资源文件

每个程序集都有自己的名称、版本等信息。这些信息可以通过AssemblyInfo.cs文件来自己定义

程序集的好处:

程序中只引用必须的程序集,减小程序的尺寸。

程序集可以封装一些代码,只提供必要的访问接口。

添加程序集引用:

添加路径、项目引用、GAC(全局程序集缓存)(了解)

不能循环添加引用

在c#中添加其他语言编写的dll文件的引用。(参考P/Invoke,在.net中调用非程序集的dll)

反射

反射:

就是动态获取程序集中的元数据来操作类型

反射中的一个重要的类(type):

获取type的来那个中方法:

通过类获得Type:Type t = typeof(Person)

通过对象获得类的Type:Type t = p.GetType()

Type类的一些常用验证方法:

bool IsAssignableFrom(Type c):(直译:是否可以从c赋值)判断当前的类型的变量是不是可以接受c类型变量的赋值。

bool IsInstanceOfType(object o):判断对象o是否是当前类的实例(当前类可以是o的类、父类、接口)

bool IsSubclassOf(Type c):判断当前类是否是类c的子类。类的事,没有接口的事。

IsAbstract,判断是否为抽象的,含接口

关于Assembly的介绍:

加载程序集方法:

Assembly asm=Assembly.LoadFile(“c:\abc.dll”);

调用Assembly的GetExportedTypes方法可以得到Assembly中定义的所有的public类型

调用Assembly的GetTypes()方法可以得到Assembly中定义的所有的类型

调用Assembly的GetType(name)方法可以得到Assembly中定义的全名为name的类型信息

动态创建对象:

Activator.CreateInstance(Type t)会动态调用类的无参构造函数创建一个对象,返回值就是创建的对象,如果类没有无参构造函数就会报错

GetConstructor(参数列表);//这个是找到带参数的构造函数

动态调用的一些成员:

MemberInfo类 抽象类,有很多子类,下面讲的类都继承自它,获取程序集成员的相关信息(类型、方法、事件、字段和属性)

PropertyInfo 获取属性

主要成员:CanRead、CanWrite、PropertyType属性类型;SetValue、GetValue:读取值,设置值,第一个参数是实例对象,因为set、get要针对具体实例,最后一个参数null。 pInfo.SetValue(p1, 30, null)

MethodInfo 获取方法

MethodInfo都是和具体对象不相关的,所以需要第一个参数指定要执行的对象。

FieldInfo 获取字段

EventInfo 获取事件

反射若干场景(了解):

1.插件机制,保证了程序的封装性,同时提高了程序的可扩展性。

2.asp.net中根据用户访问的页面动态创建页面对象,比如访问Index.aspx,则根据访问的页面名称Index,通过反射动态创建该类型的对象。(在aspx页面中执行<%=System.Reflection.Assembly.GetExecutingAssembly().Location %>,查看dll中页面生成的的类名)

3.数据访问层中使用工厂模式时,根据配置文件动态创建数据访问层对象。

4.各种框架中,修改配置文件即可实现不同效果,都用到了反射。

5.访问类中的私有成员

6.各种需要动态创建类对象的场景都可以使用

隐式类型:

var关键字(在编译时已经能确定变量的类型了。并不是弱类型。)

var i = 5;//int

var j = 23.56;//double

var k = "C Sharp";//string

var x;//错误

var y = null;//错误

var z = { 1, 2, 3 };//错误 var z=new[] {1,2,3};//正确。

var 强类型.根据后面的值自动推断类型,编译时把推断的类型替换掉var

只是方便程序员使用而已。

不能作为类成员的类型、不能用作方法的参数,返回值。(只能用作局部变量的类型推断)

匿名类型:

var p1 = new { Id = 1, Name = "YJingLee", Age = 22 };//属性也不需要申明

var p2 = new { Id = 2, Name = "XieQing", Age = 25 };

数组

var intArray = new[] { 2, 3, 5, 6 };

var strArray = new[] { "Hello", "World" };

var objArray= new[] { new { Name = "YJingLee", Age = 22 }, new { Name = "XieQing", Age = 25 } };

扩展方法:

将扩展方法放到一个单独的类中,类声明为static(静态类),方法是静态方法,并且在第一个string上增加this。哇,string类“增加”扩展方法方法了,这只是假象,本质上仍然是静态方法,只不过C#提供了这样一个便利给大家,扩展方法内部不能调用被扩展类的私有、protected的东西。

声明扩展方法的步骤:类必须是static,方法是static,第一个参数是被扩展的对象,前面标注this(this 数据类型 参数名)。使用扩展方法的时候必须保证扩展方法类已经在当前代码中using

初始化器:

对象初始化器

Student stu= new Student(){ Id = 1, Name = "YJingLee", Age = 22 };

更方便给对象赋值,在构造函数之后执行赋值,看IL代码。

集合初始化器

List<int> num = new List<int> (){ 0, 1, 2, 6, 7, 8, 9 };

List< Student > stus= new List< Student >

{ new Student{Id=1,Name="YJingLee",Age=22},

new Student{Id=2,Name="XieQing",Age=25}, };

XML(可扩展标记语言)

Xml语法特点:

  1. 严格区分大小写
  2. 有且只能有一个根节点
  3. 有开始标签必须有结束标签
  4. 属性必须使用双引号
  5. 没有预定义标签与html不一样
  6. 文档声明:<?xml version="1.0" encoding="utf-8"?>
  7. 注释:<!-- -->
  8. CDATA区:即原意文本-<![CDATA[…]]>
  9. 注意编码问题,文本文件实际编码要与文档声明中的编码一致。

Xml读写(Dom XmlDocumnet demo):

l 两种方式,推荐使用第二种:

n XmlDocument

n XDocument、(XElement、XAttribute)

XmlDocument xdoc=new XmlDocument();

//文档声明

xdoc.AppendChild(xdoc.CreateXmlDeclaration("1.0","utf-8",null));

//添加根节点

XmlElement xeroot=xdoc.CreateElement("Order");

xdoc.AppendChild(xeroot);

XmlElement xeCust =xdoc.CreateElment("CustomerName");

xeCust.InnerText="老杨";

xeroot.AppendChild(xeCust);

XmlElement XeOrderName=xdoc.CreateElment("OrderName");

xeorderName.InnerText ="bj200000";

Xeroot.AppendChild(xeOrderName);

XmlElement xeItem=xdoc.CreateElement("Items");

xeroot.AppendChild(xeItem);

XmlElement order1=xdoc.CreateElement("OrderItem");

order1.SetAttribute("Name","电脑");

order1.SetAttribute("Count",30);

Xpath简介:

常用语法:

/AAA 选择根元素AAA

/AAA/CCC 选择AAA元素下的所有CCC子元素

/AAA/BBB/CCC 选择AAA元素下子元素BBB下所有CCC字元素

//BBB 选择所有BBB子元素

//* 选择所有元素

/AAA/BBB[1] 选择AAA下第一个BBB子元素

//@id 选择所有有id属性的元素

//BBB[@id] 选择有id属性的BBB元素

//BBB[NOT(@*)] 选择没有属性的BBB元素

//BBB[@id=’b1’] 选择id为b1的BBB元素

//*[COUNT(BBB)=2] 选择含有两个BBB子元素的元素

等等…….. 用的时候可以查找

深拷贝与浅拷贝

深拷贝是把所有的数据都拷贝一份,包括引用都会拷贝,而浅拷贝只是把值类型拷贝一份,而引用类型则没有。

图例:

浅拷贝的实现(demo):

/// <summary>

/// 实现对象的浅拷贝

/// </summary>

/// <returns></returns>

public Person QianKaoBei()

{

//MemberwiseClone()方法从object类中继承下来

//作用就是把当前对象浅拷贝一份

//浅拷贝当前对象

return (Person)this.MemberwiseClone();

}

深拷贝(序列化实现):

static object DeepCopy(object src)

{

BinaryFormatter Formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));

using (MemoryStream stream = new MemoryStream())

{

Formatter.Serialize(stream, src);

stream.Position = 0;

return Formatter.Deserialize(stream);

}

}

Attribute特性(attribute)

是被指定给某一声明的一则附加的声明性信息

就是一个标签,在使用当前类的地方,通过反射获取该特性

Attribute就是类,Attribute类名一般都以Attribute结尾,使用的时候不用加Attribute这个结尾。使用Attribute的时候给的参数其实就是构造函数

反编译DisplaynameAttribute,发现没有特殊代码。标签本身是没有含义,只是起到标注的作用,具体怎么解释、使用这个标识,是由使用者来决定:属性视图窗口、C#编译器。相当于在放上画一个“拆”,本身这个字没有含义。

自定义特性(核心 反射):

Attribute都从System. Attribute类继承,类名一般以Attribute结尾

创建构造函数

标记类的用途—AttributeUsage标记(标记的标记):AttributeTargets:可以添加到哪些成员上。AllowMultiple:是否允许在一个成员上标记这个Attribute的多个实例,默认false。标注在Attribute类的类名上方。

Attribute只是给类、成员做标记,本身没有什么意义,不会发生任何动作,就像小偷踩点在门上做标记(StealableAttribute)一样,具体这个标记会起到什么作用是由使用这个类、成员的代码决定的。

Property.GetCustomerAttribute()



相关评论