前言👻
上一篇文章介绍了C#的OOP思想,不知道大家吃透了没,本篇文章是C#基础知识的最后一篇啦
看完这篇文章大家是不是都学会了C#呢,嘿嘿
下面开始介绍本篇的内容了——接口、命名空间、预处理指令、正则表达式、异常处理、文件的输入与输出
接口(interface)🎉
接口定义了所有类继承接口时应遵循的语法合同。
接口定义了语法合同 “是什么” 部分,派生类定义了语法合同 “怎么做” 部分。
接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。成员的定义是派生类的责任。接口提供了派生类应遵循的标准结构。
接口使得实现接口的类或结构在形式上保持一致。
抽象类在某种程度上与接口类似,但是,它们大多只是用在当只有少数方法由基类声明由派生类实现时。
定义接口: MyInterface.cs
接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的。下面是一个接口声明的实例:
interface IMyInterface { void MethodToImplement(); }
以上代码定义了接口 IMyInterface。通常接口命令以 I 字母开头,这个接口只有一个方法 MethodToImplement(),没有参数和返回值,当然我们可以按照需求设置参数和返回值。
值得注意的是,该方法并没有具体的实现。
接下来我们来实现以上接口:InterfaceImplementer.cs
实例 using System; interface IMyInterface { // 接口成员 void MethodToImplement(); } class InterfaceImplementer : IMyInterface { static void Main() { InterfaceImplementer iImp = new InterfaceImplementer(); iImp.MethodToImplement(); } public void MethodToImplement() { Console.WriteLine("MethodToImplement() called."); } }
InterfaceImplementer 类实现了 IMyInterface 接口,接口的实现与类的继承语法格式类似:
class InterfaceImplementer : IMyInterface
继承接口后,我们需要实现接口的方法 MethodToImplement() , 方法名必须与接口定义的方法名一致。
接口继承: InterfaceInheritance.cs
以下实例定义了两个接口 IMyInterface 和 IParentInterface。
如果一个接口继承其他接口,那么实现类或结构就需要实现所有接口的成员。
以下实例 IMyInterface 继承了 IParentInterface 接口,因此接口实现类必须实现 MethodToImplement() 和 ParentInterfaceMethod() 方法:
实例 using System; interface IParentInterface { void ParentInterfaceMethod(); } interface IMyInterface : IParentInterface { void MethodToImplement(); } class InterfaceImplementer : IMyInterface { static void Main() { InterfaceImplementer iImp = new InterfaceImplementer(); iImp.MethodToImplement(); iImp.ParentInterfaceMethod(); } public void MethodToImplement() { Console.WriteLine("MethodToImplement() called."); } public void ParentInterfaceMethod() { Console.WriteLine("ParentInterfaceMethod() called."); } }
实例输出结果为:
MethodToImplement() called.
ParentInterfaceMethod() called.
C# 命名空间(Namespace)🎈
命名空间的设计目的是提供一种让一组名称与其他名称分隔开的方式。在一个命名空间中声明的类的名称与另一个命名空间中声明的相同的类的名称不冲突。
我们举一个计算机系统中的例子,一个文件夹(目录)中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件可以重名。
定义命名空间
命名空间的定义是以关键字 namespace 开始,后跟命名空间的名称,如下所示:
namespace namespace_name { // 代码声明 }
为了调用支持命名空间版本的函数或变量,会把命名空间的名称置于前面,如下所示:
namespace_name.item_name; • 1
下面的程序演示了命名空间的用法:
实例 using System; namespace first_space { class namespace_cl { public void func() { Console.WriteLine("Inside first_space"); } } } namespace second_space { class namespace_cl { public void func() { Console.WriteLine("Inside second_space"); } } } class TestClass { static void Main(string[] args) { first_space.namespace_cl fc = new first_space.namespace_cl(); second_space.namespace_cl sc = new second_space.namespace_cl(); fc.func(); sc.func(); Console.ReadKey(); } }
当上面的代码被编译和执行时,它会产生下列结果:
Inside first_space
Inside second_space
using 关键字
using 关键字表明程序使用的是给定命名空间中的名称。例如,我们在程序中使用 System 命名空间,其中定义了类 Console。我们可以只写:
Console.WriteLine ("Hello there");
我们可以写完全限定名称,如下:
System.Console.WriteLine("Hello there");
也可以使用 using 命名空间指令,这样在使用的时候就不用在前面加上命名空间名称。该指令告诉编译器随后的代码使用了指定命名空间中的名称。下面的代码演示了命名空间的应用。
让我们使用 using 指定重写上面的实例:
实例 using System; using first_space; using second_space; namespace first_space { class abc { public void func() { Console.WriteLine("Inside first_space"); } } } namespace second_space { class efg { public void func() { Console.WriteLine("Inside second_space"); } } } class TestClass { static void Main(string[] args) { abc fc = new abc(); efg sc = new efg(); fc.func(); sc.func(); Console.ReadKey(); } }
当上面的代码被编译和执行时,它会产生下列结果:
Inside first_space
Inside second_space
嵌套命名空间
命名空间可以被嵌套,即您可以在一个命名空间内定义另一个命名空间,如下所示:
namespace namespace_name1 { // 代码声明 namespace namespace_name2 { // 代码声明 } }
可以使用点(.)运算符访问嵌套的命名空间的成员,如下所示:
实例 using System; using SomeNameSpace; using SomeNameSpace.Nested; namespace SomeNameSpace { public class MyClass { static void Main() { Console.WriteLine("In SomeNameSpace"); Nested.NestedNameSpaceClass.SayHello(); } } // 内嵌命名空间 namespace Nested { public class NestedNameSpaceClass { public static void SayHello() { Console.WriteLine("In Nested"); } } } }
当上面的代码被编译和执行时,它会产生下列结果:
In SomeNameSpace
In Nested
C# 预处理器指令🎄
预处理器指令指导编译器在实际编译开始之前对信息进行预处理。
所有的预处理器指令都是以 # 开始。且在一行上,只有空白字符可以出现在预处理器指令之前。预处理器指令不是语句,所以它们不以分号(;)结束。
C# 编译器没有一个单独的预处理器,但是,指令被处理时就像是有一个单独的预处理器一样。在 C# 中,预处理器指令用于在条件编译中起作用。与 C 和 C++ 不同的是,它们不是用来创建宏。一个预处理器指令必须是该行上的唯一指令。
C# 预处理器指令列表
下表列出了 C# 中可用的预处理器指令:
#define 预处理器
#define 预处理器指令创建符号常量。
#define 允许定义一个符号,这样,通过使用符号作为传递给 #if 指令的表达式,表达式将返回 true。它的语法如下:
#define symbol
下面的程序说明了这点:
实例 #define PI using System; namespace PreprocessorDAppl { class Program { static void Main(string[] args) { #if (PI) Console.WriteLine("PI is defined"); #else Console.WriteLine("PI is not defined"); #endif Console.ReadKey(); } } }
当上面的代码被编译和执行时,它会产生下列结果:
PI is defined
条件指令
可以使用 #if 指令来创建一个条件指令。条件指令用于测试符号是否为真。如果为真,编译器会执行 #if 和下一个指令之间的代码。
条件指令的语法:
#if symbol [operator symbol]...
其中,symbol 是要测试的符号名称。也可以使用 true 和 false,或在符号前放置否定运算符。
常见运算符有:
== (等于)
!= (不等于)
&& (与)
|| (或)
也可以用括号把符号和运算符进行分组。条件指令用于在调试版本或编译指定配置时编译代码。一个以 #if 指令开始的条件指令,必须显示地以一个 #endif 指令终止。
下面的程序演示了条件指令的用法:
实例 #define DEBUG #define VC_V10 using System; public class TestClass { public static void Main() { #if (DEBUG && !VC_V10) Console.WriteLine("DEBUG is defined"); #elif (!DEBUG && VC_V10) Console.WriteLine("VC_V10 is defined"); #elif (DEBUG && VC_V10) Console.WriteLine("DEBUG and VC_V10 are defined"); #else Console.WriteLine("DEBUG and VC_V10 are not defined"); #endif Console.ReadKey(); } }
当上面的代码被编译和执行时,它会产生下列结果:
DEBUG and VC_V10 are defined
C# 正则表达式🔔
正则表达式 是一种匹配输入文本的模式。
.Net 框架提供了允许这种匹配的正则表达式引擎。
模式由一个或多个字符、运算符和结构组成。
如果还不理解正则表达式可以阅读正则表达式 - 教程。
定义正则表达式
下面列出了用于定义正则表达式的各种类别的字符、运算符和结构。
字符转义
字符类
定位点
分组构造
限定符
反向引用构造
备用构造
替换
杂项构造
字符转义
正则表达式中的反斜杠字符(\)指示其后跟的字符是特殊字符,或应按原义解释该字符。
下表列出了转义字符:
字符类
字符类与一组字符中的任何一个字符匹配。
下表列出了字符类:
分组构造
分组构造描述了正则表达式的子表达式,通常用于捕获输入字符串的子字符串。
这一部分比较难于理解,可以阅读 正则表达式-选择 、正则表达式的先行断言(lookahead)和后行断言(lookbehind) 帮助理解。
下表列出了分组构造:
实例 using System; using System.Text.RegularExpressions; public class Example { public static void Main() { string input = "1851 1999 1950 1905 2003"; string pattern = @"(?<=19)\d{2}\b"; foreach (Match match in Regex.Matches(input, pattern)) Console.WriteLine(match.Value); } }