Class,一个继承他的类叫subClass,那么subClass也算是baseClass类型的,可以有这样的写法baseClass bc=new subClass()
创新互联建站专注于企业全网整合营销推广、网站重做改版、沐川网站定制设计、自适应品牌网站建设、H5技术、成都商城网站开发、集团公司官网建设、外贸网站制作、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为沐川等各大城市提供网站开发制作服务。
接口也是一样,如果一个类MyClass实现了借口一个接口interfaceClass,你事实上可以把MyClass叫做interfaceClass的子类,可以有这样的写法interfaceClass ic=new MyClass()
这就是所说的多态的一部分基础。可以举个实在点的例子,比如你想写一个方法叫EnumAll,参数是一个类的实例,作用是例举出该实例中的每个子元素并打印出元素的ToString(如窗体的子元素是窗体中的控件,数组的子元素就不用说了吧),你就遇到两个问题
首先EnumAll参数的类型是什么。参数应该可以是一个Form类型,因为窗口中有很多控件,使用EnumAll和一个Form的实例做参数可以打印出包含在该参数窗体中的每个控件的名字;但是一个数组Object[]类型应该也可以使用EnumAll方法,EnumAll可以列举Object[]中的每个元素并打印。你是要把方法写成void EnumAll(Form e)还是写成void EnumAll(Object[] e)?
然后就是EnumAll怎样实现才能得到不同类型的实例的子元素?如果是void EnumAll(Form e)的形式,要想得到子元素要用
foreach(Control c in e.Controls)
{
Console.WriteLine(c.ToString());
}
的写法,如果数组要用
for(int i=0;ie.length;++i)
{
Console.WriteLine(e[i].ToString());
}
的实现方法。
Form和Object[]是两种完全不沾边的类型,那么EnumAll到底该怎么写?
这时就可以使用接口,可以定义一个接口
interface IEnumable
{
Object next();//返回下一个子元素的方法
}
然后使Form和Object[]类型都实现IEnumable接口(实现方法是不同的,如前面所说),然后这样写EnumAll方法:
void EnumAll(IEnumable e)//一开始就说了,实现接口的类都可以算是接口的子类
{Object o;
while((o=e.next)!=null)
{
Console.WriteLine(o.ToString());
}
}
于是解决了上面的问题。
不知道有没有说清楚,如果理解了上面举的例子算是初步了解接口了,接口的多继承和多态性还有很多内容。
另外,上面的东西只是举例子,虽然C#中确实有IEnumable接口,但其定义要复杂的多,我只是举个简化的自己编的例子^_^。C#的(应该说是FCL吧)很多类都实现了IEnumalbe接口,像集合类和数组等。
FCL是.NET框架类库,Framework Class Library,不论在C#,J#,VB.NET或其他.NET开发语言中使用的.NET提供的类都是FCL中的类,就是说,.NET的开发其实是和语言无关的。不同语言编写的程序由于使用同一类库(其实等于被翻译成了同一种中间语言,Common Intermediate Language, CIL),使得各种不同语言写的程序集可以通用。
WNetAddConnection 创建同一个网络资源的永久性连接
WNetAddConnection2 创建同一个网络资源的连接
WNetAddConnection3 创建同一个网络资源的连接
WNetCancelConnection 结束一个网络连接
WNetCancelConnection2 结束一个网络连接
WNetCloseEnum 结束一次枚举操作
WNetConnectionDialog 启动一个标准对话框,以便建立同网络资源的连接
WNetDisconnectDialog 启动一个标准对话框,以便断开同网络资源的连接
WNetEnumResource 枚举网络资源
WNetGetConnection 获取本地或已连接的一个资源的网络名称
WNetGetLastError 获取网络错误的扩展错误信息
WNetGetUniversalName 获取网络中一个文件的远程名称以及/或者UNC(统一命名规范)名称
WNetGetUser 获取一个网络资源用以连接的名字
WNetOpenEnum 启动对网络资源进行枚举的过程
1.WNetAddConnection
VB声明
Declare Function WNetAddConnection Lib "mpr.dll" Alias "WNetAddConnectionA" (ByVal lpszNetPath As String, ByVal lpszPassword As String, ByVal lpszLocalName As String) As Long
说明
创建同一个网络资源的永久性连接
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
lpszNetPath String,要连接的网络名
lpszPassword String,可选的一个密码。如为vbNullString,表示采用当前用户的默认密码。如为一个空字串,则不用任何密码
lpszLocalName String,资源的本地名称。(例如,F: 和 LPT1:)
2.WNetAddConnection2
VB声明
Declare Function WNetAddConnection2 Lib "mpr.dll" Alias "WNetAddConnection2A" (lpNetResource As NETRESOURCE, ByVal lpPassword As String, ByVal lpUserName As String, ByVal dwFlags As Long) As Long
说明
创建同一个网络资源的连接
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
lpNetResource NETRESOURCE,在这个结构中设置了下述字段,对要连接的网络资源进行了定义:dwType, lpLocalName (可为 vbNullString), lpRemoteName, lpProvider (设为 vbNullString 表示用默认提供者)。该结构的其他所有变量都会被忽略
lpPassword String,可选的一个密码。如为vbNullString,表示采用当前用户的默认密码。如为一个空字串,则不用任何密码
lpUserName String,用于连接的用户名。如为vbNullString,表示使用当前用户
dwFlags Long,设为零;或指定常数CONNECT_UPDATE_PROFILE,表示创建永久性连接
3.WNetAddConnection3
VB声明
Declare Function WNetAddConnection3 Lib "mpr.dll" Alias "WNetAddConnection3A" (ByVal hwnd As Long, lpNetResource As NETRESOURCE, ByVal lpPassword As String, ByVal lpUserName As String, ByVal dwFlags As Long)
说明
创建同一个网络资源的连接。这个函数与WNetAddConnection2类似,只是它允许我们为这个函数显示的对话框指定一个物主窗口
返回值
Long,
参数表
参数 类型及说明
hwnd Long,指定一个窗口句柄,用作本函数创建的对话框的父窗口
lpNetResource NETRESOURCE,在这个结构中设置了下述字段,对要连接的网络资源进行了定义:dwType, lpLocalName (可为 vbNullString), lpRemoteName, lpProvider (设为 vbNullString 表示用默认提供者)。该结构的其他所有变量都会被忽略
lpPassword String,可选的一个密码。如为vbNullString,表示采用当前用户的默认密码。如为一个空字串,则不用任何密码
lpUserName String,用于连接的用户名。如为vbNullString,表示使用当前用户
dwFlags Long,设为零;或指定常数CONNECT_UPDATE_PROFILE,表示创建永久性连接
4.WNetCancelConnection
VB声明
Declare Function WNetCancelConnection Lib "mpr.dll" Alias "WNetCancelConnectionA" (ByVal lpszName As String, ByVal bForce As Long) As Long
说明
结束一个网络连接
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
lpszName String,已连接资源的远程名称或本地名称
bForce Long,如为TRUE,表示断开连接(即使连接的资源上正有打开的文件或作业)
5.WNetCancelConnection2
VB声明
Declare Function WNetCancelConnection2 Lib "mpr.dll" Alias "WNetCancelConnection2A" (ByVal lpName As String, ByVal dwFlags As Long, ByVal fForce As Long) As Long
说明
结束一个网络连接
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
lpszName String,已连接资源的远程名称或本地名称
dwFlags Long,设为零或CONNECT_UPDATE_PROFILE。如为零,而且建立的是永久性连接,则在windows下次重新启动时仍会重新连接
fForce Long,如为TRUE,表示强制断开连接(即使连接的资源上正有打开的文件或作业)
6.WNetCloseEnum
VB声明
Declare Function WNetCloseEnum Lib "mpr.dll" Alias "WNetCloseEnum" (ByVal hEnum As Long) As Long
说明
结束一次枚举操作
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
hEnum Long,由 WNetOpenEnum函数返回的一个枚举句柄
7.WNetConnectionDialog
VB声明
Declare Function WNetConnectionDialog Lib "mpr.dll" Alias "WNetConnectionDialog" (ByVal hwnd As Long, ByVal dwType As Long) As Long
说明
启动一个标准对话框,以便建立同网络资源的连接
返回值
Long,零表示成功。如用户取消了操作,则返回-1。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
hwnd Long,指定要成为对话框父窗口的一个窗口的句柄
dwType Long,设成RESOURCETYPE_DISK,浏览磁盘资源
8.WNetDisconnectDialog
VB声明
Declare Function WNetDisconnectDialog Lib "mpr.dll" Alias "WNetDisconnectDialog" (ByVal hwnd As Long, ByVal dwType As Long) As Long
说明
启动一个标准对话框,以便断开同网络资源的连接
返回值
Long,零表示成功。如用户取消了操作,则返回-1。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
hwnd Long,指定要成为对话框父窗口的一个窗口的句柄
dwType Long,设成RESOURCETYPE_DISK 或 RESOURCETYPE_PRINT,决定要断开的是磁盘还是打印机资源
9.WNetEnumResource
VB声明
Declare Function WNetEnumResource Lib "mpr.dll" Alias "WNetEnumResourceA" (ByVal hEnum As Long, lpcCount As Long, lpBuffer As Any, lpBufferSize As Long) As Long
说明
枚举网络资源
返回值
Long,零表示成功。ERROR_NO_MORE_ITEMS表示不剩下可以枚举的条目。ERROR_MORE_DATA表示条目不能装入lpBuffer。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
hEnum Long,从WNetOpenEnum函数返回的一个句柄
lpcCount Long,最初设为要枚举的最大资源数量;或设为-1,表示枚举尽可能多的资源。一旦返回,就会设为实际枚举的资源数量
lpBuffer Any,通常是一个字节缓冲区的首字节。该缓冲区装载了枚举信息(可按引用声明为Byte)
lpBufferSize Long,以字节为单位指定lpBuffer数组的长度。如缓冲区不够大,则设为需要的缓冲区长度
注解
枚举网络条目时,最好用vb一次枚举一个资源。尽量不要使用这个函数同时枚举许多网络资源的功能
10.WNetGetConnection
VB声明
Declare Function WNetGetConnection Lib "mpr.dll" Alias "WNetGetConnectionA" (ByVal lpszLocalName As String, ByVal lpszRemoteName As String, cbRemoteName As Long) As Long
说明
获取本地或已连接的一个资源的网络名称
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
lpszLocalName String,本地设备的名字
lpszRemoteName String,指定一个字串缓冲区,用于装载设备的资源名称
cbRemoteName Long,lpszRemoteName缓冲区的字符数量。如缓冲区不够大,则设为需要的缓冲区长度
11.WNetGetLastError
VB声明
Declare Function WNetGetLastError Lib "mpr.dll" Alias "WNetGetLastErrorA" (lpError As Long, ByVal lpErrorBuf As String, ByVal nErrorBufSize As Long, ByVal lpNameBuf As String, ByVal nNameBufSize As Long) As Long
说明
获取网络错误的扩展错误信息
返回值
Long,零表示成功。ERROR_INVALID_ADDRESS表示缓冲区无效
参数表
参数 类型及说明
lpError Long,指定一个变量,用于装载网络错误代码。具体的代码由网络供应商决定
lpErrorBuf String,指定一个字串缓冲区,用于装载网络错误的说明
nErrorBufSize Long,lpErrorBuf缓冲区包含的字符数量
lpNameBuf String,用于装载网络供应商名字的字串缓冲区
nNameBufSize Long,lpNameBuf缓冲区的字符数量
12.WNetGetUniversalName
VB声明
Declare Function WNetGetUniversalName Lib "mpr" Alias "WNetGetUniversalNameA" (ByVal lpLocalPath As String, ByVal dwInfoLevel As Long, lpBuffer As Any, lpBufferSize As Long) As Long
说明
获取网络中一个文件的远程名称以及/或者UNC(统一命名规范)名称。例如,假设一个已连接的远程驱动器是\\othersystem\CDrive,它对应的本地驱动器是F:,而且在它的子目录temp中包含了文件xyz.doc。那么运算结果如下:LocalPath xyz.doc 或 f:\temp\xyz.doc(或者文件的任何相对路径名)
UNC 名称: \\othersystem\CDrive\temp\xyz.doc
连接名称: \\othersystem\CDrive
剩余名称: \temp\xyz.doc
它们分别对应于由这个函数装载的REMOTE_NAME_INFO结构的字段,对该结构的定义如下:
Type REMOTE_NAME_INFO
pUniversalName As Long
pConnectionName As Long
pRemainingPath As Long
End Type
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
lpLocalPath String,磁盘文件的名字
dwInfoLevel Long,下述常数之一:
UNIVERSAL_NAME_INFO_LEVEL 只设置pUniversalName字段
REMOTE_NAME_INFO_LEVEL 设置REMOTE_NAME_INFO结构中的所有三个字段
lpBuffer Any,指定用于装载UNC信息的一个缓冲区。缓冲区起点与一个REMOTE_NAME_INFO结构对应
lpBufferSize Long,以字节为单位指定lpBuffer缓冲区的长度。如缓冲区不够大,则设为需要的缓冲区长度
13.WNetGetUser
VB声明
Declare Function WNetGetUser Lib "mpr.dll" Alias "WNetGetUserA" (ByVal lpName As String, ByVal lpUserName As String, lpnLength As Long) As Long
说明
获取一个网络资源用以连接的名字
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
lpName String,指定已连接资源的远程名称或本地名称。用vbNullString获取当前用户的名字
lpUserName String,用于装载用户名的一个字串缓冲区
lpnLength Long,lpUserName缓冲区的长度。如缓冲区不够大,则自动设为需要的缓冲区长度
14.WNetOpenEnum
VB声明
Declare Function WNetOpenEnum Lib "mpr.dll" Alias "WNetOpenEnumA" (ByVal dwScope As Long, ByVal dwType As Long, ByVal dwUsage As Long, lpNetResource As NETRESOURCE, lphEnum As Long) As Long
说明
启动对网络资源进行枚举的过程。这个函数会返回由WNetEnumResource函数用于枚举资源所用的一个句柄
返回值
Long,零表示成功。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数 类型及说明
dwScope Long,指定要枚举的资源范围。可设为下述常数之一:
RESOURCE_CONNECTED 枚举已连接的资源(忽略dwUsage)
RESOURCE_GLOBALNET 枚举所有资源
RESOURCE_REMEMBERED 只枚举永久性连接
dwType Long,下述常数之一
RESOURCE_ANY 枚举所有类型的网络资源
RESOURCE_DISK 枚举磁盘资源
RESOURCE_PRINT 枚举打印资源
dwUsage Long,可设为零,表示枚举所有资源;或设为下述常数的一个或两个:
RESOURCEUSAGE_CONNECTABLE 只枚举那些能够连接的资源
RESOURCEUSAGE_CONTAINER 只枚举包含了其他资源的资源
lpNetResource NETRESOURCE,这个结构指定了一个容器资源。该函数会枚举包含于这里指定的某个指定资源内的资源。如设为NULL(把声明变成ByVal As Long),那么函数会枚举顶级网络资源。倘若在dwScope参数里没有指定RESOURCE_GLOBALNET,那么必须为NULL
lphEnum Long,指定一个变量,用于装载一个枚举句柄。该句柄由WNetEnumResource函数使用。必须用WNetCloseEnum函数将其清除
C#(C-Sharp)是Microsoft的新编程语言,被誉为“C/C++家族中第一种面向组件的语言”。然而,不管它自己宣称的是什么,许多人认为C#更像是Java的一种克隆,或者是Microsoft用来替代Java的产品。事实是否是这样的呢?
本文的比较结果表明,C#不止是Java的同胞那么简单。如果你是一个Java开发者,想要学习C#或者了解更多有关C#的知识,那么本文就是你必须把最初10分钟投入于其中的所在。
一、C#、C++和Java
C#的语言规范由Microsoft的Anders Hejlsberg与Scott Wiltamuth编写。在当前Microsoft天花乱坠的宣传中,对C#和C++、Java作一番比较总是很有趣的。考虑到当前IT媒体的舆论倾向,如果你早就知道C#更接近Java而不是C++,事情也不值得大惊小怪。对于刚刚加入这场讨论的读者,下面的表1让你自己作出判断。显然,结论应该是:Java和C#虽然不是孪生子,但C#最主要的特色却更接近Java而不是C++。
表1:比较C#、C++和Java最重要的功能
功能 C# C++ Java
继承 允许继承单个类,允许实现多个接口 允许从多个类继承 允许继承单个类,允许实现多个接口
接口实现 通过“interface”关键词 通过抽象类 通过“interface”关键词
内存管理 由运行时环境管理,使用垃圾收集器 需要手工管理 由运行时环境管理,使用垃圾收集器
指针 支持,但只在很少使用的非安全模式下才支持。通常以引用取代指针 支持,一种很常用的功能。 完全不支持。代之以引用。
源代码编译后的形式 .NET中间语言(IL) 可执行代码 字节码
单一的公共基类 是 否 是
异常处理 异常处理 返回错误 异常处理。
了解表1总结的重要语言功能之后,请继续往下阅读,了解C#和Java的一些重要区别。
二、语言规范的比较
2.1、简单数据类型
简单数据类型(Primitive)在C#中称为值类型,C#预定义的简单数据类型比Java多。例如,C#有unit,即无符号整数。表2列出了所有C#的预定义数据类型:
表2:C#中的值类型
类型 说明
object 所有类型的最终极的基类
string 字符串类型;字符串是一个Unicode字符的序列
sbyte 8位带符号整数
short 16位带符号整数
int 32位带符号整数
long 64位带符号整数
byte 8位无符号整数
ushort 16位无符号整数
uint 32位无符号整数
ulong 64位无符号整数
float 单精度浮点数类型
double 双精度浮点数类型
bool 布尔类型;bool值或者是true,或者是false
char 字符类型;一个char值即是一个Unicode字符
decimal 有28位有效数字的高精度小数类型
2.2、常量
忘掉Java中的static final修饰符。在C#中,常量可以用const关键词声明。
public const int x = 55;
此外,C#的设计者还增加了readonly关键词。如果编译器编译时未能确定常量值,你可以使用readonly关键词。readonly域只能通过初始化器或类的构造函数设置。
2.3、公用类的入口点
在Java中,公用类的入口点是一个名为main的公用静态方法。main方法的参数是String对象数组,它没有返回值。在C#中,main方法变成了公用静态方法Main(大写的M),Main方法的参数也是一个String对象数组,而且也没有返回值,如下面的原型声明所示:
public static void Main(String[] args)
但是,C#的Main方法不局限于此。如果不向Main方法传递任何参数,你可以使用上述Main方法的一个重载版本,即不带参数列表的版本。也就是说,下面的Main方法也是一个合法的入口点:
public static void Main()
另外,如果你认为有必要的话,Main方法还可以返回一个int。例如,下面代码中的Main方法返回1:
using System;
public class Hello {
public static int Main() {
Console.WriteLine("Done");
return 1;
}
}
与此相对,在Java中重载main方法是不合法的。
2.4、switch语句
在Java中,switch语句只能处理整数。但C#中的switch语句不同,它还能够处理字符变量。请考虑下面用switch语句处理字符串变量的C#代码:
using System;
public class Hello {
public static void Main(String[] args) {
switch (args[0]) {
case "老板":
Console.WriteLine("早上好!我们随时准备为您效劳!");
break;
case "雇员":
Console.WriteLine("早上好!你可以开始工作了!");
break;
default:
Console.WriteLine("早上好!祝你好运!");
break;
}
}
}
与Java中的switch不同,C#的switch语句要求每一个case块或者在块的末尾提供一个break语句,或者用goto转到switch内的其他case标签。
2.5、foreach语句
foreach语句枚举集合中的各个元素,为集合中的每一个元素执行一次代码块。请参见下面的例子。
using System;
public class Hello {
public static void Main(String[] args) {
foreach (String arg in args)
Console.WriteLine(arg);
}
}
如果在运行这个执行文件的时候指定了参数,比如“Hello Peter Kevin Richard”,则程序的输出将是下面几行文字:
Peter
Kevin
Richard
2.6、C#没有移位操作符
C#支持uint和ulong之类的无符号变量类型。因此,在C#中,右移操作符(即“”)对于无符号变量类型和带符号变量类型(比如int和long)的处理方式不同。右移uint和ulong丢弃低位并把空出的高位设置为零;但对于int和long类型的变量,“”操作符丢弃低位,同时,只有当变量值是正数时,“”才把空出的高位设置成零;如果“”操作的是一个负数,空出的高位被设置成为1。
Java中不存在无符号的变量类型。因此,我们用“”操作符在右移时引入负号位;否则,使用“”操作符。
2.7、goto关键词
Java不用goto关键词。在C#中,goto允许你转到指定的标签。不过,C#以特别谨慎的态度对待goto,比如它不允许goto转入到语句块的内部。在Java中,你可以用带标签的语句加上break或continue取代C#中的goto。
2.8、声明数组
在Java中,数组的声明方法非常灵活,实际上有许多种声明方法都属于合法的方法。例如,下面的几行代码是等价的:
int[] x = { 0, 1, 2, 3 };
int x[] = { 0, 1, 2, 3 };
但在C#中,只有第一行代码合法,[]不能放到变量名字之后。
2.9、包
在C#中,包(Package)被称为名称空间。把名称空间引入C#程序的关键词是“using”。例如,“using System;”这个语句引入了System名称空间。
然而,与Java不同的是,C#允许为名称空间或者名称空间中的类指定别名:
using TheConsole = System.Console;
public class Hello {
public static void Main() {
TheConsole.WriteLine("使用别名");
}
}
虽然从概念上看,Java的包类似于.NET的名称空间。然而,两者的实现方式不同。在Java中,包的名字同时也是实际存在的实体,它决定了放置.java文件的目录结构。在C#校�锢淼陌�吐呒�拿�浦�涫峭耆�掷氲模�簿褪撬担��瓶占涞拿�植换岫晕锢淼拇虬�绞讲��魏斡跋臁T贑#中,每一个源代码文件可以从属于多个名称空间,而且它可以容纳多个公共类。
.NET中包的实体称为程序集(Assembly)。每一个程序集包含一个manifest结构。manifest列举程序集所包含的文件,控制哪些类型和资源被显露到程序集之外,并把对这些类型和资源的引用映射到包含这些类型与资源的文件。程序集是自包含的,一个程序集可以放置到单一的文件之内,也可以分割成多个文件。.NET的这种封装机制解决了DLL文件所面临的问题,即臭名昭著的DLL Hell问题。
2.10、默认包
在Java中,java.lang包是默认的包,它无需显式导入就已经自动包含。例如,要把一些文本输出到控制台,你可以使用下面的代码:
System.out.println("Hello world from Java");
C#中不存在默认的包。如果要向控制台输出文本,你使用System名称空间Console对象的WriteLine方法。但是,你必须显式导入所有的类。代码如下:
using System;
public class Hello {
public static void Main() {
Console.WriteLine("Hello world from C#");
}
}
2.11、面向对象
Java和C#都是完全面向对象的语言。在面向对象编程的三大原则方面,这两种语言接近得不能再接近。
继承:这两种语言都支持类的单一继承,但类可以实现多个接口。所有类都从一个公共的基类继承。
封装与可见性:无论是在Java还是C#中,你都可以决定类成员是否可见。除了C#的internal访问修饰符之外,两者的可见性机制非常相似。
多态性:Java和C#都支持某些形式的多态性机制,且两者实现方法非常类似。
2.12、可访问性
类的每个成员都有特定类型的可访问性。C#中的访问修饰符与Java中的基本对应,但多出了一个internal。简而言之,C#有5种类型的可访问性,如下所示:
public:成员可以从任何代码访问。
protected:成员只能从派生类访问。
internal:成员只能从同一程序集的内部访问。
protected internal:成员只能从同一程序集内的派生类访问。
private:成员只能在当前类的内部访问。
2.13、派生类
在Java中,我们用关键词“extends”实现继承。C#采用了C++的类派生语法。例如,下面的代码显示了如何派生父类Control从而创建出新类Button:
public class Button: Control { . . }
2.14、最终类
由于C#中不存在final关键词,如果想要某个类不再被派生,你可以使用sealed关键词,如下例所示:
sealed class FinalClass { . . }
2.15、接口
接口这个概念在C#和Java中非常相似。接口的关键词是interface,一个接口可以扩展一个或者多个其他接口。按照惯例,接口的名字以大写字母“I”开头。下面的代码是C#接口的一个例子,它与Java中的接口完全一样:
interface IShape { void Draw(); }
扩展接口的语法与扩展类的语法一样。例如,下例的IRectangularShape接口扩展IShape接口(即,从IShape接口派生出IRectangularShape接口)。
interface IRectangularShape: IShape { int GetWidth(); }
如果你从两个或者两个以上的接口派生,父接口的名字列表用逗号分隔,如下面的代码所示:
interface INewInterface: IParent1, IParent2 { }
然而,与Java不同,C#中的接口不能包含域(Field)。
另外还要注意,在C#中,接口内的所有方法默认都是公用方法。在Java中,方法声明可以带有public修饰符(即使这并非必要),但在C#中,显式为接口的方法指定public修饰符是非法的。例如,下面的C#接口将产生一个编译错误。
interface IShape { public void Draw(); }
2.16、is和as操作符
C#中的is操作符与Java中的instanceof操作符一样,两者都可以用来测试某个对象的实例是否属于特定的类型。在Java中没有与C#中的as操作符等价的操作符。as操作符与is操作符非常相似,但它更富有“进取心”:如果类型正确的话,as操作符会尝试把被测试的对象引用转换成目标类型;否则,它把变量引用设置成null。
为正确理解as操作符,首先请考虑下面这个例子中is操作符的运用。这个例子包含一个IShape接口,以及两个实现了IShape接口的类Rectangle和Circle。
using System;
interface IShape {
void draw();
}
public class Rectangle: IShape {
public void draw() {
}
public int GetWidth() {
return 6;
}
}
public class Circle: IShape {
public void draw() {
}
public int GetRadius() {
return 5;
}
}
public class LetsDraw {
public static void Main(String[] args) {
IShape shape = null;
if (args[0] == "rectangle") {
shape = new Rectangle();
}
else if (args[0] == "circle") {
shape = new Circle();
}
if (shape is Rectangle) {
Rectangle rectangle = (Rectangle) shape;
Console.WriteLine("Width : " + rectangle.GetWidth());
}
if (shape is Circle) {
Circle circle = (Circle) shape;
Console.WriteLine("Radius : " + circle.GetRadius());
}
}
}
编译好代码之后,用户可以输入“rectangle”或者“circle”作为Main方法的参数。如果用户输入的是“circle”,则shape被实例化成为一个Circle类型的对象;反之,如果用户输入的是“rectangle”,则shape被实例化成为Rectangle类型的对象。随后,程序用is操作符测试shape的变量类型:如果shape是一个矩形,则shape被转换成为Rectangle对象,我们调用它的GetWidth方法;如果shape是一个圆,则shape被转换成为一个Circle对象,我们调用它的GetRadius方法。
如果使用as操作符,则上述代码可以改成如下形式:
using System;
interface IShape {
void draw();
}
public class Rectangle: IShape {
public void draw() {
}
public int GetWidth() {
return 6;
}
}
public class Circle: IShape {
public void draw() {
}
public int GetRadius() {
return 5;
}
}
public class LetsDraw {
public static void Main(String[] args) {
IShape shape = null;
if (args[0] == "rectangle") {
shape = new Rectangle();
}
else if (args[0] == "circle") {
shape = new Circle();
}
Rectangle rectangle = shape as Rectangle;
if (rectangle != null) {
Console.WriteLine("Width : " + rectangle.GetWidth());
}
else {
Circle circle = shape as Circle;
if (circle != null)
Console.WriteLine("Radius : " + circle.GetRadius());
}
}
}
在上面代码的粗体部分中,我们在没有测试shape对象类型的情况下,就用as操作符把shape转换成Rectangle类型的对象。如果shape正好是一个Rectangle,则shape被转换成为Rectangle类型的对象并保存到rectangle变量,然后我们调用它的GetWidth方法。如果这种转换失败,则我们进行第二次尝试。这一次,shape被转换成为Circle类型的对象并保存到circle变量。如果shape确实是一个Circle对象,则circle现在引用了一个Circle对象,我们调用它的GetRadius方法。
2.17、库
C#没有自己的类库。但是,C#共享了.NET的类库。当然,.NET类库也可以用于其他.NET语言,比如VB.NET或者JScript.NET。值得一提的是StringBuilder类,它是对String类的补充。StringBuilder类与Java的StringBuffer类非常相似。
2.18、垃圾收集
C++已经让我们认识到手工管理内存是多么缺乏效率和浪费时间。当你在C++中创建了一个对象,你就必须手工地拆除这个对象。代码越复杂,这个任务也越困难。Java用垃圾收集器来解决这个问题,由垃圾收集器搜集不再使用的对象并释放内存。C#同样采用了这种方法。应该说,如果你也在开发一种新的OOP语言,追随这条道路是一种非常自然的选择。C#仍旧保留了C++的内存手工管理方法,它适合在速度极端重要的场合使用,而在Java中这是不允许的。
2.19、异常处理
如果你听说C#使用与Java相似的异常处理机制,你不会为此而惊讶,对吧?在C#中,所有的异常都从一个名为Exception的类派生(听起来很熟悉?)另外,正如在Java中一样,你还有熟悉的try和catch语句。Exception类属于.NET System名称空间的一部分。
三、Java没有的功能
C#出生在Java成熟之后,因此,C#拥有一些Java(目前)还没有的绝妙功能也就不足为奇。
3.1、枚举器
枚举器即enum类型(Enumerator,或称为计数器),它是一个相关常量的集合。精确地说,enum类型声明为一组相关的符号常量定义了一个类型名字。例如,你可以创建一个名为Fruit(水果)的枚举器,把它作为一个变量值的类型使用,从而把变量可能的取值范围限制为枚举器中出现的值。
public class Demo {
public enum Fruit {
Apple, Banana, Cherry, Durian
}
public void Process(Fruit fruit) {
switch (fruit) {
case Fruit.Apple:
...
break;
case Fruit.Banana:
...
break;
case Fruit.Cherry:
...
break;
case Fruit.Durian:
...
break;
}
}
}
在上例的Process方法中,虽然你可以用int作为myVar变量的类型,但是,使用枚举器Fruit之后,变量的取值范围限制到了Applet、Banana、Cherry和Durian这几个值之内。与int相比,enum的可读性更好,自我说明能力更强。
3.2、结构
结构(Struct)与类很相似。然而,类是作为一种引用类型在堆中创建,而结构是一种值类型,它存储在栈中或者是嵌入式的。因此,只要谨慎运用,结构要比类快。结构可以实现接口,可以象类一样拥有成员,但结构不支持继承。
然而,简单地用结构来取代类可能导致惨重损失。这是因为,结构是以值的方式传递,由于这种传递方式要把值复制到新的位置,所以传递一个“肥胖的”结构需要较大的开销。而对于类,传递的时候只需传递它的引用。
下面是一个结构的例子。注意它与类非常相似,只要把单词“struct”替换成“class”,你就得到了一个类。
struct Point {
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
3.3、属性
C#类除了可以拥有域(Field)之外,它还可以拥有属性(Property)。属性是一个与类或对象关联的命名的特征。属性是域的一种自然扩展――两者都是有类型、有名字的类成员。然而,和域不同的是,属性不表示存储位置;相反,属性拥有存取器(accessor),存取器定义了读取或者写入属性值时必须执行的代码。因此,属性提供了一种把动作和读取、写入对象属性值的操作关联起来的机制,而且它们允许属性值通过计算得到。
在C#中,属性通过属性声明语法定义。属性声明语法的第一部分与域声明很相似,第二部分包括一个set过程和/或一个get过程。例如,在下面的例子中,PropertyDemo类定义了一个Prop属性。
public class PropertyDemo {
private string prop;
public string Prop {
get {
return prop;
}
set {
prop = value;
}
}
}
如果属性既允许读取也允许写入,如PropertyDemo类的Prop属性,则它同时拥有get和set存取过程。当我们读取属性的值时,get存取过程被调用;当我们写入属性值时,set存取过程被调用。在set存取过程中,属性的新值在一个隐含的value参数中给出。
与读取和写入域的方法一样,属性也可以用同样的语法读取和写入。例如,下面的代码实例化了一个PropertyDemo类,然后写入、读取它的Prop属性。
PropertyDemo pd = new PropertyDemo();
pd.Prop = "123"; // set
string s = pd.Prop; // get
3.4、以引用方式传递简单数据类型的参数
在Java中,当你把一个简单数据类型的值作为参数传递给方法时,参数总是以值的方式传递――即,系统将为被调用的方法创建一个参数值的副本。在C#中,你可以用引用的方式传递一个简单数据类型的值。此时,被调用的方法将直接使用传递给它的那个值――也就是说,如果在被调用方法内部修改了参数的值,则原来的变量值也随之改变。
在C#中以引用方式传递值时,我们使用ref关键词。例如,如果编译并运行下面的代码,你将在控制台上看到输出结果16。注意i值被传递给ProcessNumber之后是如何被改变的。
using System;
public class PassByReference {
public static void Main(String[] args) {
int i = 8;
ProcessNumber(ref i);
Console.WriteLine(i);
}
public static void ProcessNumber(ref int j) {
j = 16;
}
}
C#中还有一个允许以引用方式传递参数的关键词out,它与ref相似。但是,使用out时,作为参数传递的变量在传递之前不必具有已知的值。在上例中,如果整数i在传递给ProcessNumber方法之前没有初始化,则代码将出错。如果用out来取代ref,你就可以传递一个未经初始化的值,如下面这个修改后的例子所示。
using System;
public class PassByReference {
public static void Main(String[] args) {
int i;
ProcessNumber(out i);
Console.WriteLine(i);
}
public static void ProcessNumber(out int j) {
j = 16;
}
}
经过修改之后,虽然i值在传递给ProcessNumber方法之前没有初始化,但PassByReference类能够顺利通过编译。
3.5、C#保留了指针
对于那些觉得自己能够恰到好处地运用指针并乐意手工进行内存管理的开发者来说,在C#中,他们仍旧可以用既不安全也不容易使用的“古老的”指针来提高程序的性能。C#提供了支持“不安全”(unsafe)代码的能力,这种代码能够直接操作指针,能够“固定”对象以便临时地阻止垃圾收集器移动对象。无论从开发者还是用户的眼光来看,这种对“不安全”代码的支持其实是一种安全功能。“不安全”的代码必须用unsafe关键词显式地标明,因此开发者不可能在无意之中使用“不安全”的代码。同时,C#编译器又和执行引擎协作,保证了“不安全”的代码不能伪装成为安全代码。
using System;
class UsePointer {
unsafe static void PointerDemo(byte[] arr) {
.
.
}
}
C#中的unsafe代码适合在下列情形下使用:当速度极端重要时,或者当对象需要与现有的软件(比如COM对象或者DLL形式的C代码)交互时。
3.6、代理
代理(delegate)可以看作C++或者其他语言中的函数指针。然而,与函数指针不同的是,C#中的代理是面向对象的、类型安全的、可靠的。而且,函数指针只能用来引用静态函数,但代理既能够引用静态方法,也能够引用实例方法。代理用来封装可调用方法。你可以在类里面编写方法并在该方法上创建代理,此后这个代理就可以被传递到第二个方法。这样,第二个方法就可以调用第一个方法。
代理是从公共基类System.Delegate派生的引用类型。定义和使用代理包括三个步骤:声明,创建实例,调用。代理用delegate声明语法声明。例如,一个不需要参数且没有返回值的代理可以用如下代码声明:
delegate void TheDelegate();
创建代理实例的语法是:使用new关键词,并引用一个实例或类方法,该方法必须符合代理指定的特征。一旦创建了代理的实例,我们就可以用调用方法的语法调用它。
3.7、包装和解除包装
在面向对象的编程语言中,我们通常使用的是对象。但为了提高速度,C#也提供了简单数据类型。因此,C#程序既包含一大堆的对象,又有大量的值。在这种环境下,让这两者协同工作始终是一个不可回避的问题,你必须要有一种让引用和值进行通信的方法。
在C#以及.NET运行时环境中,这个“通信”问题通过包装(Boxing)和解除包装(Unboxing)解决。包装是一种让值类型看起来象引用类型的处理过程。当一个值类型(简单数据类型)被用于一个要求或者可以使用对象的场合时,包装操作自动进行。包装一个value-type值的步骤包括:分配一个对象实例,然后把value-type值复制到对象实例。
解除包装所执行的动作与包装相反,它把一个引用类型转换成值类型。解除包装操作的步骤包括:首先检查并确认对象实例确实是给定value-type的一个经过包装的值,然后从对象实例复制出值。
Java对该问题的处理方式略有不同。Java为每一种简单数据类型提供了一个对应的类封装器。例如,用Integer类封装int类型,用Byte类封装byte类型。
【结束语】本文为你比较了C#和Java。这两种语言很相似,然而,说C#是Java的克隆或许已经大大地言过其实。面向对象、中间语言这类概念并不是什么新东西。如果你准备设计一种面向对象的新语言,而且它必须在一个受管理的安全环境内运行,你难道不会搞出与C#差不多的东西吗?
首先添加一个系统的语音COM组件的引用microsoft speech object library然后在程序中声明一个语音类dim RC As SpeechLib.SpSharedRecoContext这个类有一些事件,如果你要处理它的一些事件,可以用withevent来声明然后在窗体LOAD事件或你需要的地方先创建一个实例RC = New SpeechLib.SpSharedRecoContext当一个RC被实例化后,系统就会运行语音识别程序.前提是你的系统已经正确安装这个功能.一般默认就已经安装好的.其次提醒一下,WIN7的语音识别比XP的好N倍.从阅读到侦听都好很多.然后就可以在你需要阅读的地方使用RC.Voice.Speak("hello 我", 11)11那里是一些枚举,用来标识系统用前台还是后台或其他方式来阅读文字,简单的来说就是阅读的时候不会卡住你的程序.你可以选其他的枚举来试试作用.以上为阅读部分.如果需要程序听你说话,则需要声明一个侦听类dim RG As SpeechLib.ISpeechRecoGrammar在初始化时将之与上面的RC建立关系,此时则必须要用withevent来声明上面的RC,因为涉及电脑听到你的语音后,会触发一个事件,并将听到的内容传递到该事件.其次,要让系统听到的解析为命令,就必须准备一个XML结构的文件来保存那些固定的命令.如果电脑在XML文件中找不到那些固定命令或同时不属于系统命令,电脑将会将其解释为听写.RG = RC.CreateGrammar '(0)
RG.CmdLoadFromFile("听到.xml", SpeechLib.SpeechLoadOption.SLODynamic)
RG.CmdSetRuleIdState(0, SpeechLib.SpeechRuleState.SGDSActive)然后写一个过程来处理听到的事件Private Sub 听到命令(ByVal StreamNumber As Integer, ByVal StreamPosition As Object, ByVal RecognitionType As SpeechLib.SpeechRecognitionType, ByVal 话语 As SpeechLib.ISpeechRecoResult) Handles RC.Recognition RC.Voice.Speak("我听到了" 话语.PhraseInfo.GetText, 11)End Sub以上为侦听部分.下面列一个XML的例文?xml version="1.0" encoding="gb2312"?
GRAMMAR LANGID="804"
RULE NAME="命令" TOPLEVEL="ACTIVE"
L
P打开播放器
P上我的QQ
P关闭你自己 /L
/RULE
/GRAMMAR要让系统正确地侦听到你说的话,前提你必须运行语音识别程序并让其激活到"正在聆听"状态.并且你必须有一个能正常使用的话筒而且保证话筒已经打开.(废话-_-|||)以上就是用VB.NET语音识别的最基本的一些操作.希望对你有帮助.更深入的内容有兴趣的话可以和我一起研究.
VB可以是维生素B族药品的总称,也可以是Visual Basic编程程序简称。
维生素B(Vitamin B)也作维他命B,是某些维生素的总称,它们常常来自于相同的食物来源,如酵母等。维生素B最初被认为是像维生素C那样具有单一结构的有机化合物。
后来的研究证明它是一组有着不同结构的化合物,于是它的成员有了独立的名称,如维生素B1,而维生素B成为了一个总称,有的时候也被称为维生素B族、维生素B杂或维生素B复合群。
维生素B都是水溶性维生素,它们是协同作用,调节新陈代谢,维持皮肤和肌肉的健康,增进免疫系统和神经系统的功能,促进细胞生长和分裂(包括促进红血球的产生,预防贫血发生)。
Visual Basic是一种由 公司开发的结构化的、模块化的、面向对象的、包含协助开发环境的事件驱动为机制的可视化程序设计语言。从任何标准来说,VB都是世界上使用人数最多的语言——不管是盛赞VB的开发者还是抱怨VB的开发者的数量。它源自于BASIC编程语言。VB拥有图形用户界面(GUI)和快速应用程序开发(RAD)系统,可以轻易的使用DAO、RDO、ADO连接数据库,或者轻松的创建ActiveX控件。程序员可以轻松的使用VB提供的组件快速建立一个应用程序。
下面表格标识了一些可用来创建用户自定义数值格式的字符:
(0)
数字占位符。显示一位数字或是零。如果表达式在格式字符串中 0 的位置上有一位数字存在,那么就显示出来;否则,就以零显示。如果数值的位数少于格式表达式中零的位数(无论是小数点的左方或右方),那么就把前面或后面的零补足。如果数值的小数点右方位数多于格式表达式中小数点右面零的位数,那么就四舍五入到有零的位数的最后一位。如果数值的小数点左方位数多于格式表达式中小数点左面零的位数,那么多出的部分都要不加修饰地显示出来。
(#)
数字占位符。显示一位数字或什么都不显示。如果表达式在格式字符串中“#”的位置上有数字存在,那么就显示出来;否则,该位置就什么都不显示。
此符号的工作原理和“0”数字占位符大致相同,不同之处只有在当表达式中数值的位数少于“#”的位数(无论是小数点左方或右方)时,不会把前面或后面的零显示出来。
(.)
小数点占位符。在一些国别是用逗号来当小数点的。小数点占位符用来决定在小数点左右可显示多少位数。如果格式表达式在此符号左边只有正负号,那么小于 1 的数字将以小数点为开头。如想在小数前有“0”的话,那么请在小数点占位符前加上“0”这个数字占位符。小数点占位符的实际字符在格式输出时要看系统的数字格式而定。
(%)
百分比符号占位符。表达式乘以 100。而百分比字符 (%) 会插入到格式字符串中出现的位置上。
(,)
千分位符号占位符。在一些国别,是用句点来当千位符号。千位符号主要是把数值小数点左边超过四位数以上分出千位。如果格式中在数字占位符(0 或 #)周围包含有千分位符号,则指定的是标准的千分位符号使用法。两个邻近的千分位符号或一个千分位符号紧接在小数点左边(不管小数位是否指定),其意思为“将数值除以 1000,按需要四舍五入”。例如,可以用格式字符串 "##0,," 将 1 亿表示成 100。数值小于 1 百万的话表示成“0”,两个邻近的千分位符号除了紧接在小数点左边以外,在任何位置出现时均简单地视为指定了使用千分位符号。小数点占位符的真正字符在格式输出时,需视系统识别的数字格式而定。
(:)
时间分隔符。在一些国别,可能用其他符号来当时间分隔符。在格式化时间值时,时间分隔符可以用来分隔时、分和秒。时间分隔符的真正字符在格式输出时,取决于系统的设置。
(/)
日期分隔符。在一些国别,可能用其他符号来当日期分隔符。在格式化日期数值时,日期分隔符可以用来分隔年、月、日。日期分隔符的真正字符在格式输出时,取决于系统设置。
(E- E+ e- e+)
科学格式。如果格式表达式在 E-、E+、e- 或 e+ 的右方含有至少一个数字占位符(0 或 #),那么数值将表示成科学格式,而 E 或 e 会被安置在数字和指数之间。E 或 e 右方数字占位符的个数取决于指数位数。使用 E- 或 e- 时,会用减号来表示负的乘幂。使用 E+ 或 e+ 时,会用减号来表示负的乘幂并用加号来表示正的乘幂。
- + $ ( )
显示一个原义字符。如想显示那些列出的字符之外的字符时,可以用反斜杠 ( \ ) 字符作前缀或以双引号 (" ") 括起来。
(\)
将格式字符串中下一个字符显示出来。如想显示一作为原义字符并有特殊含义的字符,可将此字符置于反斜杠 (\) 之后。反斜杠本身并不会显示出来。而使用反斜杠 (\) 的效果和使用双引号是一样的。如想显示反斜杠字符,可使用两个反斜杠 (\\)。
那些不能显示为原义字符的字符是日期格式字符和时间格式字符(a, c, d, h, m, n, p, q, s, t, w, y, / 和 :)、数值格式字符(#, 0, %, E, e, 逗点和句点)和字符串格式字符(@, , , 和 !)。
("ABC")
显示双引号 (" ") 之内的字符串。如在代码中想在 format 中包含一个字符串,必须用 Chr(34) 将文本括起来(34 为双引号 (") 的字符代码)。