c#的特性,反射,索引器的作用,以及委托 有什么用?

西西软件下载最安全的下载网站、值得信赖的软件下载站!
您的位置:
→ c#泛型使用详解:泛型特点、泛型继承、泛型接口、泛型委托
泛型:通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。在.NET类库中处处都可以看到泛型的身影,尤其是数组和集合中,泛型的存在也大大提高了程序员的开发效率。更重要的是,C#的泛型比C++的模板使用更加安全,并且通过避免装箱和拆箱操作来达到性能提升的目的。因此,我们很有必要掌握并善用这个强大的语言特性。 C#泛型特点:1、如果实例化泛型类型的参数相同,那么JIT编辑器会重复使用该类型,因此C#的动态泛型能力避免了C++静态模板可能导致的代码膨胀的问题。2、C#泛型类型携带有丰富的元数据,因此C#的泛型类型可以应用于强大的反射技术。3、C#的泛型采用“基类、接口、构造器,值类型/引用类型”的约束方式来实现对类型参数的“显示约束”,提高了类型安全的同时,也丧失了C++模板基于“签名”的隐式约束所具有的高灵活性C#泛型继承:C#除了可以单独声明泛型类型(包括类与结构)外,也可以在基类中包含泛型类型的声明。但基类如果是泛型类,它的类型要么以实例化,要么来源于子类(同样是泛型类型)声明的类型参数,看如下类型class C&U,V&class D:C&string,int&class E&U,V&:C&U,V&class F&U,V&:C&string,int&class G:C&U,V&&&//非法E类型为C类型提供了U、V,也就是上面说的来源于子类F类型继承于C&string,int&,个人认为可以看成F继承一个非泛型的类G类型为非法的,因为G类型不是泛型,C是泛型,G无法给C提供泛型的实例化泛型类型的成员:泛型类型的成员可以使用泛型类型声明中的类型参数。但类型参数如果没有任何约束,则只能在该类型上使用从System.Object继承的公有成员。如下图:泛型接口:泛型接口的类型参数要么已实例化,要么来源于实现类声明的类型参数泛型委托:泛型委托支持在委托返回值和参数上应用参数类型,这些参数类型同样可以附带合法的约束delegate bool MyDelegate&T&(T value);class MyClass{&&&&static bool F(int i){...}&&&&static bool G(string s){...}&&&&static void&Main()&&&&{&&&&&&&&MyDelegate&string& p2 = G;&&&&&&&&MyDelegate&int& p1 = new MyDelegate&int&(F);&&&&}}泛型方法:1、C#泛型机制只支持“在方法声明上包含类型参数”――即泛型方法。2、C#泛型机制不支持在除方法外的其他成员(包括属性、事件、索引器、构造器、析构器)的声明上包含类型参数,但这些成员本身可以包含在泛型类型中,并使用泛型类型的类型参数。3、泛型方法既可以包含在泛型类型中,也可以包含在非泛型类型中。泛型方法声明:如下public static int FunctionName&T&(T value){...}泛型方法的重载:public void Function1&T&(T a);public void Function1&U&(U a);这样是不能构成泛型方法的重载。因为编译器无法确定泛型类型T和U是否不同,也就无法确定这两个方法是否不同public void Function1&T&(int x);public void Function1(int x);这样可以构成重载public void Function1&T&(T t) where T:A;public void Function1&T&(T t) where T:B;这样不能构成泛型方法的重载。因为编译器无法确定约束条件中的A和B是否不同,也就无法确定这两个方法是否不同泛型方法重写:在重写的过程中,抽象类中的抽象方法的约束是被默认继承的。如下:abstract class Base{&&&&public abstract T F&T,U&(T t,U u) where U:T;&&&&public abstract T G&T&(T t) where T:IC}class MyClass:Base{&&&&public override X F&X,Y&(X x,Y y){...}&&&&public override T G&T&(T t) where T:IComparable{}}对于MyClass中两个重写的方法来说F方法是合法的,约束被默认继承G方法是非法的,指定任何约束都是多余的泛型约束:1、C#泛型要求对“所有泛型类型或泛型方法的类型参数”的任何假定,都要基于“显式的约束”,以维护C#所要求的类型安全。2、“显式约束”由where子句表达,可以指定“基类约束”,“接口约束”,“构造器约束”,“值类型/引用类型约束”共四种约束。3、“显式约束”并非必须,如果没有指定“显式约束”,范型类型参数将只能访问System.Object类型中的公有方法。例如:在开始的例子中,定义的那个obj成员变量。比如我们在开始的那个例子中加入一个Test1类,在它当中定义两个公共方法Func1、Func2,如下图:我们今天来讨论下泛型的用法。首先说下泛型的概念,用通俗的语言来讲,泛型其实就是类的一个参数,但是要求参数必须是一个类,而不能是一个对象。很多人可能对泛型中T的作用不太理解,其中T在泛型中扮演的角色就相当于一个占位符,确切的说,是类型占位符。凡是出现T的地方都会替换成你所传递的类型。那么下面我们就来写一个泛型的例子,让大家体验一下泛型的威力。首先咱们来看常用的List&T&泛型集合01,List&T&集合,其中T可以是任何类型(int,string,数组类型,甚至是用户自定义的类类型)&&&&&&&&&&& List&string& intList = new List&string&();&&&&&&&&&&& intList.Add(&李晓玲&);&&&&&&&&&&& intList.Add(&章子怡&);&&&&&&&&&&& foreach (string item in intList)&&&&&&&&&&& {&&&&&&&&&&&&&&& Console.WriteLine(item);&&&&&&&&&&& }也可以在声明List&T&时使用类似于数组初始化器的集合初始化器。例如:List&string&& nameList=new& List&string&(){“Jack”,”Rose”,”Harvard”};(该特性在.net3.0以及更高版本中使用)List&T&常用方法:& 1. 要向泛型中添加一个元素:使用Add()方法&&&&&&&&&&&&&&&&&&&&&&& 添加多个元素:使用AddRange()方法&2.在指定位置插入元素使用Insert()方法3.访问元素可以通过索引,也可以使用foreach循环遍历4.删除元素可以使用Remove()或者RemovAt()方法,使用Clear()方法可以删除所有元素。然后来看下键值对泛型集合Dictionary&key,value&C#也为HashTable提供了泛型类型,即Dictionary&K,V&,通常称为”字典”。Dictionary&K,V&存储数据的特点:1, 存储数据的方式和哈希表类似,也是通过key/value保存元素。2, 键必须是唯一的。不能为null,但是如果值为引用类型,该值可以为空。主要属性:count:获取包含的键/值对数&&&&&&&&&&&&&&&&&&&& Keys:键的集合//02,Dictionary&K,V&集合&&&&&&&&&&& Dictionary&string, string& dic = new Dictionary&string, string&();&&&&&&&&&&& dic.Add(&01&, &李小龙&);&&&&&&&&&&& dic.Add(&02&,&李连杰&);&&&&&&&&&&& //遍历key&&&&&&&&&&& foreach (string item in dic.Keys)&&&&&&&&&&& {&&&&&&&&&&&&&&& Console.WriteLine(&key&+item+&& value&+dic[item]);&&&&&&&&&&& }&&&&&&&&&&& //一次性遍历键和值&&&&&&&&&&& foreach (KeyValuePair&string,string& item in dic)&&&&&&&&&&& {&&&&&&&&&&&&&&& Console.WriteLine(&key&+item.Key+&&& value&+item.Value);&&&&&&&&&&& }&这时候大家可能会有疑问,为什么要用泛型呢?泛型有三个好处:1,实现算法的重用。在泛型出现之前,我们为了保证性能安全而自定义强类型集合时,就需要为每种类型创建几乎相同自定义集合。这样就会重复劳动而且可维护性差。&& 2,避免拆箱和装箱。&& 这点大家可以这样理解,使用ArrayList和HashTable存取变量,会带来频繁的装箱(将值类型转换成引用类型)和拆箱(将引用类型转换成值类型)操作,对性能有所影响。3,类型安全(编译时会自动检测参数类型)泛型的特点:泛型将操作的数据类型定义为一个参数,类型参数使得设计如下类和方法成为可能。这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化类或方法的时候。使用where约束类型参数可以使用where约束类型参数:&& Where& T:struct 中T必须在其继承链中有System.ValueType值类型。Where T:class 中T必须是引用类型Where T:new()中T必须有一个默认的构造函数。在有多个约束的类型上,此约束必须列在末尾。Where& T:NameOfBaseClass中T必须派生于NameOfBaseClass指定的类。当然,泛型不仅能用在类上,也可单独用在类的方法中,它可根据方法参数的类型自动适应各种参数,这样的方法就叫做泛型方法。Public& class& Stack2{&&&&& Public& void& Push&T&(Stack&T& s,& params T[] p){&&&&&& Foreach(T& t& in& p)&&&&&& {&&&&&&&&& s.Push(t);}}}原来的类Stack一次只能Push一个数据,这个类Stack2扩展了Stack的功能,可以一次把多个数据压入Stack中,其中Push是一个泛型方法。这个方法的调用示例如下:Stack&int&& stack=new& Stack&int&(100);Stack2& mystack2=new& Stack2();mystack2.Push(x,1,2,3);string& str=string.Efor(int i=0;i&3;i++){&&& Str+=stack.Pop().ToString();}结果输出str的值是64321
阅读本文后您有什么感想? 已有
人给出评价!
访问量多的C#与NET4高级程序设计 -
  书 名: C#与NET4高级程序设计
  作 者:特罗尔森
  出版时间: 日
  开本: 16开
  定价: 149.00元
C#与NET4高级程序设计 -
  本书是C#领域久负盛名的经典著作,深入全面地叙述了C#编程语言和.NET平台核心,并以大量示例剖析相关概念。书中介绍了C#的各种语言构造、.NET2.0的类、核心API、公共言()、动态程序集和ASPNET扩展等内容;同时也介绍了.NET3.0、和.NET4中的新的编程API,包括WPF、WCF和WF的功能;另外,还介绍了最新的C#2010编程语言、、TPL、LINQ编程技术、COM与.NET的互操作性以及平台无关的.NET开发等。
  本书由微软C#MVPAndrewTroelsen编写,历经多次修订,适合各层次.NET开发人员阅读。
C#与NET4高级程序设计 -
  目 录
  第一部分 C#与.NET平台
  第1章 .NET之道 2
  1.1 .NET之前的世界 2
  1.2 .NET解决方案 5
  1.3 .NET平台构造块(CLR、CTS和CLS)简介 5
  1.4 其他支持.NET的编程语言 7
  1.5 .NET程序集概览 9
  1.6 CTS 14
  1.7 CLS 17
  1.8 CLR 18
  1.9 程序集/命名空间/类型的区别 19
  1.10 使用ildasm.exe探索程序集 24
  1.11 使用Reflector来查看程序集 26
  1.12 部署.NET运行库 27
  1.13 .NET的平台无关性 27
  1.14 小结 28
  第2章 构建C#应用程序 30
  2.1 .NET Framework 4 SDK的作用 30
  2.2 用csc.exe构建C#应用程序 31
  2.3 使用Notepad++构建.NET应用程序 36
  2.4 使用构建.NET应用程序 36
  2.5 使用Visual C# 2010 Express构建.NET应用程序 38
  2.6 使用构建.NET应用程序 40
  2.7 小结 50
  第二部分 C#核心编程结构
  第3章 C#核心编程结构Ⅰ 52
  3.1 一个简单的C#程序 52
  3.2 有趣的题外话:System.Environment类的其他成员 57
  3.3 System.Console类 58
  3.4 系统数据类型和C#简化符号 62
  3.5 使用字符串数据 70
  3.6 窄化和宽化数据类型转换 76
  3.7 隐式类型本地变量 81
  3.8 C#迭代结构 84
  3.9 条件结构和关系/相等操作符 86
  3.10 小结 89
  第4章 C#核心编程结构Ⅱ 90
  4.1 方法和参数修饰符 90
  4.2 C#中的数组操作 99
  4.3 枚举类型 105
  4.4 结构类型 109
  4.5 值类型和引用类型 112
  4.6 C#可空类型 118
  4.7 小结 121
  第5章 定义封装的类类型 122
  5.1 C#类类型 122
  5.2 构造函数 125
  5.3 this关键字的作用 128
  5.4 static关键字 133
  5.5 定义OOP的支柱 139
  5.6 C#访问修饰符 142
  5.7 第一个支柱:C#的封装服务 144
  5.8 自动属性 154
  5.9 对象语法 157
  5.10 常量数据 160
  5.11 分部类型 162
  5.12 小结 163
  第6章 继承和多态 164
  6.1 继承的基本机制 164
  6.2 回顾Visual Studio类关系图 168
  6.3 OOP的第二个支柱:继承 169
  6.4 包含/委托编程 174
  6.5 OOP的第三个支柱:C#的多态支持 176
  6.6 基类/派生类的转换规则 187
  6.7 超级父类:System.Object 189
  6.8 小结 195
  第7章  196
  7.1 错误、bug与异常 196
  7.2 .NET异常处理的作用 197
  7.3 最简单的例子 199
  7.4 配置异常的状态 202
  7.5 系统级异常(System.System-Exception) 206
  7.6 应用程序级异常(System.Applica-tionException) 207
  7.7 处理多个异常 210
  7.8 谁在引发什么异常 215
  7.9 未处理异常的后果 215
  7.10 使用Visual Studio调试未处理的异常 216
  7.11 损坏状态异常简介 217
  7.12 小结 218
  第8章 对象的生命周期 219
  8.1 类、对象和引用 219
  8.2 对象生命周期的基础 220
  8.3 应用程序根的作用 223
  8.4 对象的代 224
  8.5 .NET 1.0至.NET 3.5的并发垃圾回收 225
  8.6 .NET 4下的后台垃圾回收 225
  8.7 System.GC类型 225
  8.8 构建可终结对象 229
  8.9 构建可处置对象 231
  8.10 构建可终结类型和可处置类型 234
  8.11 延迟对象实例化 237
  8.12 小结 240
  第三部分 高级C#编程结构
  第9章 接口 242
  9.1 接口类型 242
  9.2 定义自定义接口 245
  9.3 实现接口 247
  9.4 在对象级别调用接口成员 248
  9.5 接口作为参数 250
  9.6 接口作为返回值 252
  9.7 接口类型数组 253
  9.8 使用Visual Studio 2010实现接口 253
  9.9 通过显式接口实现解决命名冲突 254
  9.10 设计接口层次结构 257
  9.11 构建可枚举类型(IEnumerable和IEnumerator) 260
  9.12 构建可克隆的对象(ICloneable) 265
  9.13 构建可比较的对象() 269
  9.14 小结 273
  第10章 泛型 274
  10.1 非泛型集合 274
  10.2 泛型类型参数的作用 281
  10.3 System.Collections.Generic命名空间 285
  10.4 创建自定义泛型方法 292
  10.5 创建自定义泛型结构和类 294
  10.6 类型参数的约束 297
  10.7 小结 300
  第11章 委托、事件和Lambda 301
  11.1 .NET委托类型 301
  11.2 在C#中定义委托类型 302
  11.3 System.MulticastDelegate与System.Delegate基类 304
  11.4 最简单的委托示例 305
  11.5 使用委托发送对象状态通知 307
  11.6 方法组转换语法 313
  11.7 委托协变 314
  11.8 泛型委托 316
  11.9 C#事件 318
  11.10 C#匿名方法 325
  11.11 Lambda表达式 328
  11.12 小结 333
  第12章 高级C#语言特性 335
  12.1 索引器方法 335
  12.2 操作符重载 339
  12.3 自定义类型转换 347
  12.4 扩展方法 352
  12.5 分部方法 360
  12.6 匿名类型 362
  12.7 指针类型 367
  12.8 小结 373
  第13章 LINQ to Object 374
  13.1 LINQ特有的编程结构 374
  13.2 LINQ的作用 377
  13.3 将LINQ查询应用于原始数组 379
  13.4 返回LINQ查询的结果 385
  13.5 将LINQ查询应用到集合对象 387
  13.6 C#LINQ查询操作符 389
  13.7 LINQ查询语句的内部表示 396
  13.8 小结 400
  第四部分 用.NET程序集编程
  第14章 .NET程序集入门 402
  14.1 定义自定义命名空间 402
  14.2 .NET程序集的作用 407
  14.3 .NET程序集的格式 409
  14.4 构建和使用单文件程序集 412
  14.5 构建和使用多文件程序集 421
  14.6 私有程序集 423
  14.7  427
  14.8 使用共享程序集 433
  14.9 配置共享程序集 435
  14.10 发行者策略程序集 439
  14.11 元素 440
  14.12 System.Configuration命名空间 441
  14.13 小结 442
  第15章 类型反射、晚期绑定和基于特性的编程 443
  15.1 类型元数据的必要性 443
  15.2 反射 447
  15.3 构建自定义的元数据查看器 450
  15.4 动态加载程序集 454
  15.5 反射共享程序集 457
  15.6 晚期绑定 458
  15.7 .NET特性的作用 461
  15.8 构建自定义特性 465
  15.9 程序集级别(和模块级别)特性 467
  15.10 使用早期绑定反射特性 469
  15.11 使用晚期绑定反射特性 470
  15.12 反射、晚期绑定和自定义特性的使用背景 471
  15.13 构建可扩展的应用程序 472
  15.14 小结 477
  第16章 进程、和对象上下文 478
  16.1 Windows进程的作用 478
  16.2 .NET平台下与进程进行交互 480
  16.3 .NET应用程序域 488
  16.4 与默认应用程序域进行交互 489
  16.5 创建新的应用程序域 492
  16.6 对象上下文边界 495
  16.7 进程、应用程序域和上下文小结 498
  16.8 小结 499
  第17章 CIL和动态程序集的作用 500
  17.1 学习CIL语法的原因 500
  17.2 CIL指令、特性和操作码 501
  17.3 入栈和出栈:CIL基于栈的本质 502
  17.4 正反向工程 504
  17.5 CIL指令和特性 510
  17.6 .NET基础类库、C#和CIL数据类型的映射 515
  17.7 在CIL中定义类型成员 516
  17.8 剖析CIL操作码 518
  17.9 使用CIL构建.NET程序集 522
  17.10 动态程序集 526
  17.11 小结 534
  第18章 动态类型和动态语言运行时 535
  18.1 dynamic关键字的作用 535
  18.2 DLR的作用 540
  18.3 使用动态类型简化后期绑定调用 542
  18.4 使用动态数据简化COM互操作 544
  18.5 使用C# 2010的特性进行COM互操作 548
  18.6 小结 552
  第五部分 .NET基础类库
  第19章 构建多线程应用程序 554
  19.1 进程、应用程序域、上下文及线程之间的关系 554
  19.2 .NET委托的简短回顾 556
  19.3 委托的 557
  19.4 异步调用方法 559
  19.5 System.Threading命名空间 564
  19.6 System.Threading.Thread类 564
  19.7 以编程方式创建次线程 567
  19.8 并发问题 572
  19.9 使用Timer Callback编程 578
  19.10 CLR线程池 579
  19.11 .NET平台下的并行编程 581
  19.12 并行LINQ查询(PLINQ) 588
  19.13 小结 590
  第20章 文件输入输出和对象序列化 591
  20.1 研究SystemIO命名空间 591
  20.2 Directory(Info)和File(Info)类型 592
  20.3 使用型 593
  20.4 使用Directory类型 596
  20.5 使用DriveInfo类类型 597
  20.6 使用FileInfo类 598
  20.7 使用File类型 601
  20.8 Stream抽象类 603
  20.9 使用StreamWriter和StreamReader类型 605
  20.10 使用StringWriter和StringReader类型 608
  20.11 使用BinaryWriter和Binary-Reader 609
  20.12 以编程方式“观察”文件 610
  20.13 对象序列化 612
  20.14 为序列化配置对象 614
  20.15 选择序列化格式化程序 616
  20.16 使用BinaryFormatter序列化对象 618
  20.17 使用SoapFormatter序列化对象 620
  20.18 使用XmlSerializer序列化对象 621
  20.19 序列化对象集合 623
  20.20 自定义Soap/Binary序列化过程 624
  20.21 小结 628
为本词条添加和相关影像
互动百科的词条(含所附图片)系由网友上传,如果涉嫌侵权,请与客服联系,我们将按照法律之相关规定及时进行处理。未经许可,禁止商业网站等复制、抓取本站内容;合理使用者,请注明来源于。
登录后使用互动百科的服务,将会得到个性化的提示和帮助,还有机会和770多万专业认证智愿者沟通。
您也可以使用以下网站账号登录:
此词条还可添加&
编辑次数:3次
参与编辑人数:3位
最近更新时间: 01:17:16
贡献光荣榜
扫描二维码用手机浏览词条
保存二维码可印刷到宣传品
扫描二维码用手机浏览词条
保存二维码可印刷到宣传品C#高手!!!为什么要引入索引器、委托、虚方法、抽象函数、接口?各在何种情况下使用?_百度知道
C#高手!!!为什么要引入索引器、委托、虚方法、抽象函数、接口?各在何种情况下使用?
提问者采纳
虚方法. 和虚方法相似.索引器可以让你写更少的代码1. 只是取了一个新名字而已.接口则是面向对象发展时.3, 而抽象函数则在父类不可以提供实现.. 4, 主要就是为了实现多态, 由子类则必须实现. 在C中就是函数指针. 不同的是虚方法(函数)在父类可以提供实现., 接口表达做什么(有人说是象什么. 面向对象时引入的, 可以让子类提供自己的实现.委托, 类描述是什么. 这个不是新东西.2.5, 需要描述可以做什么的统一描述. 让方法可以继承, 或者说是一种特殊的虚方法(函数).抽象函数.与类不同的是.行为上)
其他类似问题
索引器的相关知识
其他3条回答
这么大的问题?我觉得你只能看书了
这些都是面向对象的思想啊,使用这些东西,主要是方便在大型项目中(起码10w代码,实际上应该比这个数量级大得多)不同的程序员以及不同的小组之间可以比较容易的将自己完成的功能模块与别人完成的组合起来。
为什么?为了更方便的应用于实际情况。在何种情况下用?索引器一般用在同种数据类型的集合,比如说数组,ArrayList。虚方法为父类的一个方法,需要子类去实现的,虚方法主要是为子类提供一个规范。抽象函数指的是只有函数的定义,而没有他的实现。比如下面这个函数:abstract void getData();一般是为了定义一个规范,让子类去实现用。接口是包含抽象方法(函数)的一个类,但它只能包含抽象方法。一个类可以继承(实现)多个接口。接口用法也是一样,定义一些规范,让实现它的类去用。至于委托,他的用处太广泛了,基本上winform程序中都用到了,这个的定义和用法比较复杂,最好看书
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。的,只是加了一点点自己的东东,官方介绍的很详细,我们就一起来了解一下它的用法。
特性具有以下属性:
特性可向程序中添加元数据。所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员。
可以将一个或多个特性应用到整个程序集、模块或较小的程序元素(如类和属性)。
特性可以与方法和属性相同的方式接受参数。
程序可以使用反射检查自己的元数据或其他程序内的元数据。
这些都是官方的定义,那么对于一个初学者来说,看的懂汉字不难,但是上面的元数据是什么?
我这么通俗的解释下:
  你注意过程序及编译的时候的pdb文件了吗?pdb文件里面存储了,关于程序集内部的所有的成员信息,例如,成员的数据类型,属性类型,方法返回值,方法入参类型,就是程序及内部所有的定义信息的数据信息,是存储定义信息的一类数据信息,程序集里面的所有的关于声明类的数据信息,包括方法间调用,都是存储在元数据里面。
下面开始一同学习特性的用法:
特性可以放置在几乎所有的声明中。在 C# 中,特性的指定方法为:将括在方括号中的特性名置于其应用到的实体的声明上方。
[System.Serializable]
public class SampleClass
// Objects of this type can be serialized.
一个声明上可放置多个特性:
using System.Runtime.InteropS
void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }
某些特性对于给定实体可以指定多次。 就是一个可多次使用的特性:
[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
根据约定,所有特性名称都以单词&Attribute&结束,以便将它们与&.NET Framework&中的其他项区分。但是,在代码中使用特性时,不需要指定 attribute 后缀。例如,[DllImport] 虽等效于 [DllImportAttribute],但 DllImportAttribute 才是该特性在 .NET Framework 中的实际名称
许多特性都有参数,而这些参数可以是定位参数、未命名参数或命名参数。任何定位参数都必须按特定顺序指定并且不能省略,而命名参数是可选的且可以按任意顺序指定。首先指定定位参数。例如,这三个特性是等效的:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
第一个参数(DLL 名称)是定位参数并且总是第一个出现,其他参数为命名参数。在这种情况下,两个命名参数均默认为 false,因此可将其省略。
应用该特性的实体。例如,特性可以应用于类、特定方法或整个程序集。默认情况下,特性应用于它后面的元素。但是,您也可以将特性应用于方法还是它的参数或返回值
[target : attribute-list]
下表显示了可能的 target 值的列表。
整个程序集
当前程序集模块(不同于 Visual Basic 模块)
在类或结构中的字段
方法或 get 和 set 属性访问器
方法参数或 set 属性访问器参数
方法、属性索引器或 get 属性访问器的返回值
结构、类、接口、枚举或委托
下面的示例演示如何将特性应用于程序集和模块。&
using System.R
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]
下面的示例演示如何在 C# 中将特性应用于方法、方法参数和方法返回值。
// default: applies to method
[SomeAttr]
int Method1() { return 0; }
// applies to method
[method: SomeAttr]
int Method2() { return 0; }
// applies to return value
[return: SomeAttr]
int Method3() { return 0; }
无论规定 SomeAttr 应用于什么目标,都必须指定 return 目标,即使 SomeAttr 被定义为仅应用于返回值也是如此。 信息解析不明确的特性目标。
做下测试,它标记不再使用的程序元素。此类不能被继承。
当然我们看看其他的特性,我们就会发现特性其实是从System.Object类派生出来的一种特殊类。
&我们现在用这个构造来验证
public ObsoleteAttribute(string message, bool error)
& 参数                         类型:
& message                  &System ..::.String        描述可选的变通方法的文本字符串。
 error                    System ..::.Boolean       指示是否将使用已过时的元素视为错误的布尔值。
总之我们在使用特性的时候不要产生畏惧,就当他是特殊的类,以前怎么样用构造函数现在仍旧怎么用只是格式有点微妙的变化。
namespace 特性
class Program
static void Main(string[] args)
OldClass old = new OldClass();//2个报错,因为使用OldClass两次
old.OldMethod();//警告。因为第二个参数未指定使用已过时的元素不会视为错误
Console.ReadKey();
[Obsolete("该类已经过时",true)]//使用默认的特性目标,直接作用于紧随其后的Class OldClass
//第二个参数我这里设置为true将使用已过时的元素视为错误
class OldClass
[method: Obsolete("该方法已经过时")]
public void OldMethod()
Console.WriteLine("过时的方法!");
运行以后会出现两个错误提示,一个警告提示:
好了,现在我们在紧接着学习自定义特性,这个估计就算是相当简单了。自定义特性
可以定义一个自定义 Author特性类:
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct)
public class Author : System.Attribute
private string
public double
public Author(string name)
this.name =
version = 1.0;
类名是特性的名称,即 Author。它由 System.Attribute 派生而来,因此是自定义特性类。构造函数的参数是自定义特性的定位参数。本示例中 name 是定位参数。任何公共的读写字段或属性都是命名参数。在本例中,version 是唯一的命名参数。请注意 AttributeUsage 特性的用法,它使得 Author 特性仅在类声明中有效。
可以按如下所示使用此新特性:
[Author("P. Ackerman", version = 1.1)]
class SampleClass
// P. Ackerman's code goes here...
AttributeUsage 有一个命名参数 AllowMultiple,使用它可以使自定义特性成为一次性使用或可以使用多次的特性。在下面的代码示例中,创建了一个使用多次的特性。
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct,
AllowMultiple = true)
// multiuse attribute
public class Author : System.Attribute
在下面的代码示例中,向某个类应用了同一类型的多个特性。
[Author("P. Ackerman", version = 1.1)]
[Author("R. Koch", version = 1.2)]
class SampleClass
// P. Ackerman's code goes here...
// R. Koch's code goes here...
&如果特性类包含一个属性,则该属性必须为读写属性。
&介绍完了官方的示例是不是还是云里雾里,那么我们一起来深入解剖一下。
首先我们从上面可以总结出创建自定义特性的大概步骤:
1.应用AttributeUsage特性 虽然等效,但AttributeUsageAttribute 才是该特性在 .NET Framework 中的实际名称,它也是由 System.Attribute 派生而来。
2.声明特性类,它由 System.Attribute 派生而来。
3.声明构造函数&
4.声明特性
OVER!!!就这么回事,完了吗,我们继续剖析之重要的信息,AttributeUsage特性。
AttributeUsage特性,研究特性当然首要的要研究其构造函数。现在我们来看看他是怎么定义的。
public AttributeUsageAttribute( AttributeTargets validOn)
&参数&& validOn 类型:System.AttributeTargets 使用按位&或&运算符组合的一组值,用于指示哪些程序元素是有效的。
值和 Inherited 值列表初始化 AttributeUsageAttribute 类的新实例。
于是乎我们返回到了研究AttributeTargets的问题了。现在我们就来细心的看看他是神马!原来他是一个枚举,通过该特性可使其成员值按位组合。可以通过按位&或&运算组合 AttributeTargets 枚举值来获得首选组合。
&成员名称说明
可以对程序集应用特性。
可以对模块应用特性。
Module 指的是可移植的可执行文件(.dll 或 .exe),而非 Visual Basic 标准模块。
可以对类应用特性。
可以对结构应用特性,即值类型。
可以对枚举应用特性。
Constructor
可以对构造函数应用特性。
可以对方法应用特性。
可以对属性应用特性。
可以对字段应用特性。
可以对事件应用特性。
可以对接口应用特性。
可以对参数应用特性。
可以对委托应用特性。
ReturnValue
可以对返回值应用特性。
GenericParameter
可以对泛型参数应用特性。
目前,此特性可以应用仅于 C#、Microsoft 中间语言 (MSIL) 和发出的代码。
可以对任何应用程序元素应用特性。
&到了这里一节也就明了了,谜底都一一展现在我们的面前。
&按照上面的经验,再次开始动手来熟悉这一切,我指定了该自定义的特性不可继承,就在不解释别的了只是为了证明一下命名参数Inherited定性成功与否,总之还是很简单的。
namespace 特性
class Program
static void Main(string[] args)
GetAttributeInfo(typeof(OldClass));
Console.WriteLine("==============");
GetAttributeInfo(typeof(NewClass));
Console.ReadKey();
public static void GetAttributeInfo(Type t)
OldAttribute myattribute = (OldAttribute)Attribute.GetCustomAttribute(t, typeof(OldAttribute));
if (myattribute == null)
Console.WriteLine(t.ToString()+"类中自定义特性不存在!");
Console.WriteLine("特性描述:{0}\n加入事件{1}", myattribute.Discretion, myattribute.date);
[AttributeUsage(AttributeTargets.Class,Inherited=false)]//设置了定位参数和命名参数
//该特性适用于所有的类,而且是非继承的。
class OldAttribute : Attribute//继承自Attribute
public string Discretion
set { discretion = }
public DateT
public OldAttribute(string discretion)
this.discretion =
date = DateTime.N
//现在我们定义两类
[Old("这个类将过期")]//使用定义的新特性
class OldClass
public void OldTest()
Console.WriteLine("测试特性");
class NewClass:OldClass
public void NewTest()
Console.WriteLine("测试特性的继承");
//我们写一个方法用来获取特性信息
运行效果:
今天就到此了,睡觉觉了!希望同学们能略有所获。
阅读(...) 评论()}

我要回帖

更多关于 c 定义索引器 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信