C#代码示例_定义类
默认情况下,类声明为内部的,即只有当前项目中的代码才能访问它。可以使用internal访问修饰符关键字显示指定。
除了两个访问修饰符关键字(public, internal)外,还可以指定类是抽象的(不能实例化,只能继承,可以有抽象成员)或密封的(sealed,不能继承)。为此,可以使用两个互斥的关键字abstract或sealed。
编译器不允许派生类的可访问性高于基类。
不能再接口中使用关键字abstract和sealed,因为这两个修饰符在接口定义中是没有意义的(它们不包含实现代码,所以不能直接实例化,且必须是可以继承的)。
在.NET中使用的析构函数(由System.Object类提供)叫做Finalize(),但这不是我们用于声明析构函数的名称。使用下面的代码,而不是重写Finalize():
class MyClass { ~MyClass() { // Destructor body. } } |
类的析构函数由带有~前缀的类名(与构造函数相同)来声明。
无论在派生类上使用什么构造函数(默认的构造函数或非默认的构造函数),除非明确指定,否则就使用基类的默认构造函数。
base关键字指定.NET实例化过程使用基类中有指定参数的构造函数。
除了base关键字外,这里还可以将另一个关键字this用作构造函数初始化器。这个关键字指定在调用指定的构造函数前,.NET实例化过程对当前类使用非默认的构造函数。例如:
public class MyDerivedClass : MyBaseClass { public MyDerivedClass() : this(5,6) { } ... public MyDerivedClass (int i, int j) : base (i) { } } |
这段代码将执行下述序列:
执行System.Object.Object()构造函数。
执行MyBaseClass.MyBaseClass(int i)构造函数。
执行MyDerivedClass.MyDerivedClass(int i, int j)构造函数。
执行MyDerivedClass.MyDerivedClass()构造函数。
包含关系:一个类包含另一个类。这类似于继承关系,但包含类可以控制对被包含类的成员的访问,甚至在使用被包含类的成员前进行其他处理。
集合关系:一个类用作另一个类的多个实例的容器。这类似于对象数组,但集合有其他功能,包括索引、排序和重新设置大小等。
值类型和引用类型的一个主要区别是:值类型总是包含一个值,而引用类型可以是null,表示它们不包含值。但是,可以使用可空类型(这时泛型的一种形式)创建一个值类型,使值类型在这个方面的行为方式类似于引用类型(即可以为null)。
只有string和object简单类型是引用类型,但数组也是隐式的引用类型。
如果一个项目什么都不包含,只包含类(以及其他相关的类型定义,但没有入口点),该项目就称为类库。
类库项目编译为.dll程序集,在其他项目中添加对类库项目的引用,就可以访问它的内容,这将扩展对象提供的封装性。
应用程序使用外部库中定义的类时,可以把该应用程序称为库的客户应用程序。使用所定义的类的代码一般简称为客户代码。
接口和抽象类
相同点:都包含可以由派生类继承的成员。都不能直接实例化,但可以声明这些类型的变量。
不同点:派生类只能继承一个基类,即只能直接继承一个抽象类。而类可以使用任意多个接口。抽象类可以拥有抽象成员(没有代码体,且必须在派生类中实现,否则派生类本身必须也是抽象的)和非抽象成员(它们拥有代码体,也可以是虚拟的,这样就可以在派生类中重写)。另一方面,接口成员必须都在使用接口的类上实现——它们没有代码体。另外,按照定义,接口成员是公共的(因为它们倾向于在外部使用),但抽象类的成员可以是私有的(只要它们不是抽象的)、受保护的、内部的或受保护的内部成员(其中受保护的内部成员只能在应用程序的代码或派生类中访问)。此外,接口不能包含字段、构造函数、析构函数、静态成员或常量。
抽象类主要用作对象系列的基类,共享某些主要特性,例如,共同的目的和结构。接口则主要用于类,这些类在基础水平上有所不同,但仍可以完成某些相同的任务。
浅度和深度复制
浅度复制(shallow copy),没有考虑引用类型成员。因此,新对象中的引用成员就会指向与源对象中相同成员的对象。可以通过派生于System.Object的MemberwiseClone()方法来完成。
深度复制(deep copy),创建成员的新实例(复制值,而不复制引用)。可以实现ICloneable接口,实现其中包含的Clone()方法。这个方法返回一个类型为System.Object的值。
成员的访问级别:
- public——成员可以由任何代码访问。
- private——成员只能由类中的代码访问(如果没有使用任何关键字,就默认使用这个关键字)。
- internal——成员只能由定义它的程序集(项目)内部的代码访问。
- protected——成员只能由类或派生类中的代码访问。
后两个关键字可以合并使用,所以也有protected internal成员。它们只能由项目(更确切地讲,是程序集)中派生类的代码来访问。
定义字段
字段也可以使用关键字readonly,表示这个字段只能在执行构造函数的过程中赋值,或由初始化赋值语句赋值。例如:
class MyClass { Public readonly int MyInt=17; } |
定义方法
可以在方法定义中使用下述关键字:
- virtual——方法可以重写。
- abstract——方法必须在非抽象的派生类中重写(只用于抽象类中)。
- override——方法重写了一个基类方法(如果方法被重写,就必须使用该关键字)。
- extern——方法定义在其他地方。
public class MyBaseClass
{
public virtual void DoSomething()
{
// Base implementation.
}
} public class MyDerivedClass : MyBaseClass
{
public override sealed void DoSomething()
{
// Derived class implementation, override base implementation.
}
} }
如果使用了override, 也可以使用sealed指定在派生类中不能对这个方法作进一步的修改,即这个方法不能由派生类重写。
定义属性
属性拥有两个类似于函数的块,一个块用于获取属性的值,另一个块用于设置属性的值。这两个块也称为访问器,分别用get和set关键字来定义,可以用于控制对属性的访问级别。例如:
private int myInt; public int MyIntProp { get { return myInt; } protected set { myInt=value; } } |
属性可以使用virtual、override和abstract关键字,就像方法一样,但这几个关键字不能用于字段。访问其可以有自己的可访问性。
访问器可以使用的访问修饰符取决于属性的可访问性,访问器的可访问性不能高于它所属的属性。也就是说,私有属性对它的访问器不能包含任何可访问修饰符,而公共属性可以对其访问器使用所有的可访问修饰符。
“重构”表示使用工具修改代码,而不是手工修改。
如:为字段创建属性:右击该字段,选择Refactor|Encapsulate Field。
自动属性 |
public int MyIntProp { get; set; } |
自动属性的唯一限制是它们必须包含get和set存取器,无法使用这种方式定义只读或只写属性。
隐藏基类方法
当从基类继承一个(非抽象的)成员时,也就继承了其实现代码。如果继承的成员是虚拟的,就可以用override关键字重写这段实现代码。无论继承的成员是否为虚拟,都可以隐藏这些实现代码。
使用new关键字可以显示隐藏基类方法。
namespace test
{
public class MyBaseClass
{
public virtual void DoSomething()
{
Console.WriteLine("Base imp");
}
} public class MyDerivedClass : MyBaseClass
{
new public void DoSomething()
{
Console.WriteLine("derived imp");
}
} class Program
{
static void Main(string[] args)
{
MyDerivedClass myObj = new MyDerivedClass();
MyBaseClass myBaseObj;
myBaseObj = myObj;
myBaseObj.DoSomething(); Console.ReadLine(); }
}
}
其结果如下: Base imp
基类方法不必是虚拟的,但结果是一样的。
调用重写或隐藏的基类方法
使用base关键字,表示包含在派生类中的基类的实现代码(载控制构造函数时,其用法是类似的)。
因为base使用的是对象实例,所以在静态成员中使用它会产生错误。
还可以使用this关键字。与base一样,this也可以用在类成员的内部,且该关键字也引用对象实例。只是this引用的是当前的对象实例(即不能在静态成员中使用this关键字)。
This关键字最常用的功能是把当前对象实例的引用传递给一个方法,如下例所示:
public void doSomething() { MyTargetClass myObj=new MyTargetClass(); myObj.DoSomethingWith(this); } |
其中,被实例化的MyTargetClass实例有一个DoSomethingWith()方法,该方法带一个参数,其类型与包含上述方法的类兼容。这个参数类型可以是类的类型、由这个类继承的类类型,或者由这个类或System.Object实现的一个接口。
接口成员的定义与类成员的定义相似,但有几个重要的区别:
- 不允许使用访问修饰符(public, private, protected 或 internal),所有的接口成员都是公共的。
- 接口成员不能包含代码体。
- 接口不能定义字段成员。
- 接口成员不能用关键字static, virtual, abstract 或 sealed来定义。
- 类型定义成员是禁止的。
可以关键字new来隐藏继承了基接口的成员。例如:
interface IMyBaseInterface { void DoSomething(); } interface IMyDerivedInterface : IMyBaseInterface { new void DoSomething(); } |
在接口中定义的属性可以定义访问块get和set中的哪一个能用于该属性(或将它们同时用于该属性)。
接口可以定义为类的成员(但不能定义为其他接口的成员,因为接口不能包含类型定义)。
可以使用关键字virtual或abstract来实现接口成员。
可以使用关键字virtual或abstract来实现接口成员,但不能使用static或const。还可以在基类上实现接口成员,例如:
public interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
} public class MyBaseClass
{
public void DoSomething()
{
}
} public class MyDerivedClass : MyBaseClass, IMyInterface
{
public void DoSomethingElse()
{
}
}
继承一个实现给定接口的基类,就意为着派生类隐式地支持这个接口。
显示实现接口成员
如果显示实现接口成员,该成员就只能通过接口来访问,不能通过类来访问。隐式成员可以通过类和接口来访问。
public interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
} public class MyClass : IMyInterface
{
void IMyInterface.DoSomething()
{
}
public void DoSomeThingElse()
{
}
}
其中DoSomething()是显示实现的,而DoSomethingElse()是隐式实现的。
用非公共的可访问性添加属性存储器
如果实现带属性的接口,就必须实现匹配get/set存储器。这并不是绝对正确——如果在定义属性的接口中只包含set块,就可给类中的属性添加get块,反之亦然。但是,只有所添加的存储器的可访问修饰符比接口中定义的存储器的可访问修饰符更严格时,才能这么做。因为按照定义,接口定义的存储器是公共的,也就是说,只能添加非公共的存储器。
部分类定义(partial class definition)
把类得定义放在多个文件中。为此,只需在每个包含部分类定义的文件中对类使用partial关键字既可。例如:
public partial class MyClass { ...... } |
部分类对Windows应用程序隐藏与窗体布局相关的代码有很大的作用。在Form1类中,Windows窗体的代码存储在Form1.cs和Form1.Designer.cs中。
应用于部分类的接口也会应用于整个类。
部分类定义可以在一个部分类定义文件或者多个部分类定义文件中包含基类。但如果基类在多个定义文件中指定,它就必须是同一个基类,因为在C#中,类只能继承一个基类。
部分方法定义
部分类也可以定义部分方法。部分方法在部分类中定义,但没有方法体,在另一个部分类中包含实现代码。在这两个部分类中,都要使用partial关键字。例如:
public partial class MyClass { partial void MyPartialMethod(); } public partial class MyClass { partial void MyPartialMethod() { // Method implementation |
部分方法也可以是静态的,但它们总是私有的,且不能有返回值。他们使用的任何参数都不能是out参数,但可以是ref参数。部分方法也不能使用virtual、abstract、override、sealed和extern修饰符。
实际上,部分方法在编译代码时非常重要,其用法倒并不重要。编译代码时,如果代码包含一个没有实现代码的部分方法,编译器会完全删除该方法,还会删除对该方法的所有调用。执行代码时,不会检查实现代码,因为没有检查方法的调用。这会略微提高性能。
指定项目为解决方案的启动项目
在Solution Explorer窗口中右击该项目名,选择Set as StartUp Project菜单项。
C#代码示例_定义类的更多相关文章
- 等待唤醒机制代码实现_包子类&包子铺类和等待唤醒机制代码实现_吃货类&测试类
资源类:包子类 设置包子的属性 皮 陷 包子的状态:有 true 没有 false public class BaoZi { //皮 String pi; //陷 String xian; //包子的 ...
- C#代码示例_调试
调试信息 可使用如下两个命令输出调试信息: l Debug.WriteLine() l Trace.WriteLine() 这两个命令函数的用法几乎完全相同,但有一个重要区别.第一个命令仅在调试模式下 ...
- C#代码示例_函数
参数数组 C#允许为函数指定一个(只能指定一个)特定的参数,这个参数必须是函数定义中的最后一个参数,称为参数数组.参数数组可以使用个数不定的参数调用函数,可以使用params关键字定义它们. 参数数组 ...
- C#代码示例_集合
C#中数组实现为System.Array类得实例,它们只是集合类(Collection Classes)中的一种类型. 索引符(indexer)是一种特殊类型的属性,可以把它添加到一个类中,以提供类似 ...
- C# 代码示例_结构/数组/枚举...
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- JAVA NIO工作原理及代码示例
简介:本文主要介绍了JAVA NIO中的Buffer, Channel, Selector的工作原理以及使用它们的若干注意事项,最后是利用它们实现服务器和客户端通信的代码实例. 欢迎探讨,如有错误敬请 ...
- 转:HIBERNATE一些_方法_@注解_代码示例---写的非常好
HIBERNATE一些_方法_@注解_代码示例操作数据库7步骤 : 1 创建一个SessionFactory对象 2 创建Session对象 3 开启事务Transaction : hibernate ...
- 通讯服务类API调用的代码示例合集:短信服务、手机号归属地查询、电信基站查询等
以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 短信服务:通知类和验证码短信,全国三网合一通道,5秒内到达,费用低 ...
- 开发工具类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等
以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 六位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数 ...
随机推荐
- 移植linux-2.6.32.2到qq2440
编译该版本内核使用的编译器版本:arm-linux-gcc 3.4.1 1.获取linux-2.6.32.2 2.解压内核 3.切换到刚解压的内核目录下: cd linux-2.6.32.2 4.修改 ...
- 12款最佳Linux命令行终端工具, 20款优秀的 Linux 终端仿真器
12款最佳Linux命令行终端工具 如果你跟我一样,整天要花大量的时间使用Linux命令行,而且正在寻找一些可替代系统自带的老旧且乏味的终端软件,那你真是找对了文章.我这里搜集了一些非常有趣的 ...
- STM32学习笔记(十) CAN通讯测试(环回模式)
1.CAN通讯的理解 想学习CAN通讯,那么要对通讯协议有一定的认知.通讯协议是指通信双方对数据传送控制的一种约定.约定中包括对数据格式,同步方式,传输速度,传送步骤,检纠错方式以及控制字符定义等问题 ...
- 【ubuntu】屏幕超时关闭后不能唤醒
根据 http://blog.csdn.net/longshenlmj/article/details/18081167修改了"启动laptop_mode模式"gedit 的文件 ...
- Software Engineering: 2. Project management
resources:"Software Engineering" Ian Sommerville For most projects, important goals are: D ...
- CAD打开文件总是弹出要求选择字体怎么办
CAD打开文件总是弹出要求选择字体怎么办1.在C:\Documents and Settings\下搜索acad.fmp文件,双击用记事本打开acad.fmp文件,在最后添加内容,上面几行本来就有,不 ...
- jqGrid表格控件
一. jqGrid的加载. 1.引用相关头文件 引入CSS: <link type="text/css" rel="stylesheet" href=&q ...
- webwork
代码结构,html页面引入两个js文件,work.js和main.js work.js (function () { onmessage = function (e) { var num = e.da ...
- [笔记]CSS样式声明顺序
来自Bootstrap中文网编程规范 相关的属性声明应当归为一组,并按照下面的顺序排列: Positioning Box model Typographic Visual .declaration-o ...
- free函数
free函数 原型: void free(void *ptr) 功 能: 释放ptr指向的存储空间.被释放的空间通常被送入可用存储区池,以后可在调用malloc.realloc以及calloc函数来再 ...