目录

C# - 快速指南

C# - Overview

C#是一种现代的,通用的,面向对象的编程语言,由Microsoft开发并经欧洲计算机制造商协会(ECMA)和国际标准组织(ISO)批准。

C#是由Anders Hejlsberg及其团队在.Net Framework开发期间开发的。

C#专为公共语言基础结构(CLI)而设计,它由可执行代码和运行时环境组成,允许在不同的计算机平台和体系结构上使用各种高级语言。

以下原因使C#成为一种广泛使用的专业语言 -

  • 它是一种现代的通用编程语言
  • 它是面向对象的。
  • 它是面向组件的。
  • 这很容易学习。
  • 它是一种结构化语言。
  • 它产生有效的程序。
  • 它可以在各种计算机平台上编译。
  • 它是.Net Framework的一部分。

C#的强大编程功能

虽然C#构造紧密遵循传统的高级语言,C和C ++,并且是一种面向对象的编程语言。 它与Java有很强的相似性,它具有许多强大的编程功能,使其可以满足全球众多程序员的需求。

以下是C#的一些重要功能列表 -

  • Boolean Conditions
  • Automatic Garbage Collection
  • Standard Library
  • 程序集版本控制
  • 属性和事件
  • 代表和活动管理
  • 易于使用的泛型
  • Indexers
  • 条件编译
  • 简单的多线程
  • LINQ和Lambda表达式
  • 与Windows集成

C# - Environment

在线尝试选项

我们已经在线设置了C#编程环境,因此您可以在线编译和执行所有可用的示例。 它让您对正在阅读的内容充满信心,并使您能够使用不同的选项验证程序。 随意修改任何示例并在线执行。

使用CodingGround提供的在线编译器尝试以下示例

using System;
namespace HelloWorldApplication {
   class HelloWorld {
      static void Main(string[] args) {
         /* my first program in C# */
         Console.WriteLine("Hello World");
         Console.ReadKey();
      }
   }
}

对于本教程中给出的大多数示例,您可以在右上角的网站代码部分找到Try it选项,它将带您进入在线编译器。 所以,只要利用它,享受你的学习。

在本章中,我们将讨论创建C#编程所需的工具。 我们已经提到C#是.Net框架的一部分,用于编写.Net应用程序。 因此,在讨论运行C#程序的可用工具之前,让我们了解C#与.Net框架的关系。

.Net框架

.Net框架是一个革命性的平台,可以帮助您编写以下类型的应用程序 -

  • Windows应用程序
  • Web应用程序
  • 网页服务

.Net框架应用程序是多平台应用程序。 该框架的设计方式使其可以使用以下任何语言:C#,C ++,Visual Basic,Jscript,COBOL等。所有这些语言都可以访问框架以及相互通信。

.Net框架由客户语言(如C#)使用的庞大代码库组成。 以下是.Net框架的一些组件 -

  • 公共语言运行时(CLR)
  • .Net Framework类库
  • 通用语言规范
  • 普通型系统
  • 元数据和程序集
  • Windows窗体
  • ASP.Net和ASP.Net AJAX
  • ADO.Net
  • Windows Workflow Foundation(WF)
  • Windows Presentation Foundation
  • Windows Communication Foundation(WCF)
  • LINQ

对于每个组件执行的作业,请参阅ASP.Net - 简介 ,有关每个组件的详细信息,请参阅Microsoft的文档。

适用于C#的集成开发环境(IDE)

Microsoft为C#编程提供了以下开发工具 -

  • Visual Studio 2010(VS)
  • Visual C#2010 Express(VCE)
  • Visual Web Developer

最后两个可以从Microsoft官方网站免费获得。 使用这些工具,您可以将各种C#程序从简单的命令行应用程序编写到更复杂的应用程序。 您还可以使用基本文本编辑器(如记事本)编写C#源代码文件,并使用命令行编译器将代码编译为程序集,该编译器也是.NET Framework的一部分。

Visual C#Express和Visual Web Developer Express版本是Visual Studio的精简版本,具有相同的外观。 它们保留了Visual Studio的大多数功能。 在本教程中,我们使用了Visual C#2010 Express。

您可以从Microsoft Visual Studio下载它。 它会自动安装在您的计算机上。

注意:您需要有效的Internet连接才能安装快速版。

在Linux或Mac OS上编写C#程序

虽然.NET Framework在Windows操作系统上运行,但是有一些替代版本可以在其他操作系统上运行。 Mono是.NET Framework的开源版本,它包含一个C#编译器,可在多个操作系统上运行,包括各种Linux和Mac OS。 请检查Go Mono

Mono的既定目的不仅是能够跨平台运行Microsoft .NET应用程序,而且还为Linux开发人员带来更好的开发工具。 Mono可以在许多操作系统上运行,包括Android,BSD,iOS,Linux,OS X,Windows,Solaris和UNIX。

C# - Program Structure

在我们研究C#编程语言的基本构建块之前,让我们看一下最基本的C#程序结构,以便我们在接下来的章节中将其作为参考。

创建Hello World计划

AC#程序包括以下部分 -

  • 命名空间声明
  • A class
  • Class methods
  • 类属性
  • A Main method
  • 声明和表达
  • Comments

让我们看一下打印“Hello World”字样的简单代码 -

using System;
namespace HelloWorldApplication {
   class HelloWorld {
      static void Main(string[] args) {
         /* my first program in C# */
         Console.WriteLine("Hello World");
         Console.ReadKey();
      }
   }
}

编译和执行此代码时,会产生以下结果 -

Hello World

让我们看一下给定程序的各个部分 -

  • 程序的第一行using System; - using关键字用于在程序中包含System命名空间。 程序通常具有多个using语句。

  • 下一行有namespace声明。 namespace是类的集合。 HelloWorldApplication命名空间包含HelloWorld类。

  • 下一行有一个class声明, HelloWorld类包含程序使用的数据和方法定义。 类通常包含多个方法。 方法定义类的行为。 但是, HelloWorld类只有一个Main方法。

  • 下一行定义Main方法,它是所有C#程序的entry pointMain方法说明了类在执行时的作用。

  • 下一行/*...*/被编译器忽略,并在程序中添加comments

  • Main方法使用语句Console.WriteLine("Hello World");指定其行为Console.WriteLine("Hello World");

    WriteLineSystem命名空间中定义的Console类的方法。 该语句导致消息“Hello,World!” 显示在屏幕上。

  • 最后一行Console.ReadKey(); 适用于VS.NET用户。 这使得程序等待按键操作,并且当从Visual Studio .NET启动程序时,它会阻止屏幕快速运行和关闭。

值得注意的是以下几点 -

  • C# is case sensitive.
  • 所有语句和表达式必须以分号(;)结尾。
  • 程序执行从Main方法开始。
  • 与Java不同,程序文件名可能与类名不同。

编制和执行程序

如果您使用Visual Studio.Net编译和执行C#程序,请执行以下步骤 -

  • 启动Visual Studio。

  • 在菜单栏上,选择“文件” - >“新建” - >“项目”。

  • 从模板中选择Visual C#,然后选择Windows。

  • 选择Console Application。

  • 指定项目的名称,然后单击“确定”按钮。

  • 这将在Solution Explorer中创建一个新项目。

  • 在代码编辑器中编写代码。

  • 单击“运行”按钮或按F5键以执行项目。 将出现一个包含Hello World行的命令提示符窗口。

您可以使用命令行而不是Visual Studio IDE编译C#程序 -

  • 打开文本编辑器并添加上述代码。

  • 将文件另存为helloworld.cs

  • 打开命令提示符工具,然后转到保存文件的目录。

  • 输入csc helloworld.cs并按Enter键编译代码。

  • 如果代码中没有错误,命令提示符会将您带到下一行并生成helloworld.exe可执行文件。

  • 输入helloworld来执行您的程序。

  • 您可以在屏幕上看到输出的Hello World。

C# - Basic Syntax

C#是一种面向对象的编程语言。 在面向对象的编程方法中,程序由各种对象组成,这些对象通过动作相互交互。 对象可以采取的动作称为方法。 据说相同类型的物体具有相同的类型,或者据说属于同一类。

例如,让我们考虑一个Rectangle对象。 它具有长度和宽度等属性。 根据设计,可能需要接受这些属性的值,计算面积和显示细节的方法。

让我们看一下Rectangle类的实现并讨论C#的基本语法 -

using System;
namespace RectangleApplication {
   class Rectangle {
      // member variables
      double length;
      double width;
      public void Acceptdetails() {
         length = 4.5;    
         width = 3.5;
      }
      public double GetArea() {
         return length * width; 
      }
      public void Display() {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }
   class ExecuteRectangle {
      static void Main(string[] args) {
         Rectangle r = new Rectangle();
         r.Acceptdetails();
         r.Display();
         Console.ReadLine(); 
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Length: 4.5
Width: 3.5
Area: 15.75

using关键字

任何C#程序中的第一个语句是

using System;

using关键字用于在程序中包含名称空间。 程序可以包含多个using语句。

关键字class

class关键字用于声明一个类。

C#中的评论

注释用于解释代码。 编译器忽略注释条目。 C#程序中的多行注释以/ *开头,并以字符* /结尾,如下所示 -

/* This program demonstrates
The basic syntax of C# programming 
Language */

单行注释用'//'符号表示。 例如,

}//end class Rectangle    

成员变量

变量是类的属性或数据成员,用于存储数据。 在前面的程序中, Rectangle类有两个名为lengthwidth成员变量。

会员职能

函数是执行特定任务的语句集。 类的成员函数在类中声明。 我们的示例类Rectangle包含三个成员函数: AcceptDetailsGetAreaDisplay

实例化一个类

在前面的程序中,类ExecuteRectangle包含Main()方法并实例化Rectangle类。

标识符 (Identifiers)

标识符是用于标识类,变量,函数或任何其他用户定义项的名称。 在C#中命名类的基本规则如下 -

  • 名称必须以字母开头,后面可以跟一系列字母,数字(0 - 9)或下划线。 标识符中的第一个字符不能是数字。

  • 它不能包含任何嵌入空间或符号,例如? - +! @#%^&*()[] {}。 ; :“'/和\。但是,可以使用下划线(_)。

  • 它不应该是C#关键字。

C#关键词

关键字是为C#编译器预定义的保留字。 这些关键字不能用作标识符。 但是,如果要将这些关键字用作标识符,则可以在关键字前加上@字符。

在C#中,一些标识符在代码的上下文中具有特殊含义,例如get和set称为上下文关键字。

下表列出了C#中的保留关键字和上下文关键字 -

保留关键字
abstractasbaseboolbreakbytecase
catchcharcheckedclassconstcontinuedecimal
defaultdelegatedodoubleelseenumevent
explicitexternfalsefinallyfixedfloatfor
foreachgotoifimplicitinin (generic modifier)int
interfaceinternalislocklongnamespacenew
nullobjectoperatoroutout (generic modifier)overrideparams
privateprotectedpublicreadonlyrefreturnsbyte
sealedshortsizeofstackallocstaticstringstruct
switchthisthrowtruetrytypeofuint
ulonguncheckedunsafeushortusingvirtualvoid
volatilewhile
上下文关键字
addaliasascendingdescendingdynamicfromget
globalgroupintojoinletorderbypartial (type)
partial (method)removeselectset

C# - Data Types

C#中的变量分为以下类型 -

  • Value types
  • 参考类型
  • 指针类型

值类型

可以直接为值类型变量分配值。 它们派生自System.ValueType类。

值类型直接包含数据。 一些示例是int, char, and float ,它们分别存储数字,字母和浮点数。 声明int类型时,系统会分配内存来存储该值。

下表列出了C#2010中的可用值类型 -

类型 代表 范围 默认值
bool 布尔值 True or False False
byte8-bit unsigned integer 0到255 0
char16-bit Unicode character U +0000到U + ffff '\0'
decimal 128位精确十进制值,28-29位有效数字 (-7.9 x 10 28至7.9 x 10 28 )/ 10 0至28 0.0M
double 64位双精度浮点类型 (+/-)5.0 x 10 -324到(+/-)1.7 x 10 308 0.0D
float 32位单精度浮点类型 -3.4 x 10 38至+ 3.4 x 10 38 0.0F
int32-bit signed integer type-2,147,483,648 to 2,147,483,6470
long64-bit signed integer type-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 0L
sbyte8-bit signed integer type-128 to 1270
short16-bit signed integer type-32,768 to 32,7670
uint32-bit unsigned integer type0 to 4,294,967,2950
ulong64-bit unsigned integer type0 to 18,446,744,073,709,551,6150
ushort16-bit unsigned integer type0 to 65,5350

要在特定平台上获取类型或变量的确切大小,可以使用sizeof方法。 表达式sizeof(type)产生对象或类型的存储大小(以字节为单位)。 以下是在任何机器上获取int类型大小的示例 -

using System;
namespace DataTypeApplication {
   class Program {
      static void Main(string[] args) {
         Console.WriteLine("Size of int: {0}", sizeof(int));
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Size of int: 4

参考类型

引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。

换句话说,它们指的是存储位置。 使用多个变量,引用类型可以引用内存位置。 如果内存位置中的数据由其中一个变量更改,则另一个变量会自动反映此值的更改。 built-in引用类型的示例包括: objectdynamic,string

对象类型

Object Type是C#通用类型系统(CTS)中所有数据类型的最终基类。 Object是System.Object类的别名。 可以为对象类型分配任何其他类型,值类型,引用类型,预定义或用户定义类型的值。 但是,在分配值之前,它需要进行类型转换。

当值类型转换为对象类型时,它被称为boxing ,另一方面,当对象类型转换为值类型时,它被称为unboxing

object obj;
obj = 100; // this is boxing

动态类型

您可以在动态数据类型变量中存储任何类型的值。 对这些类型的变量进行类型检查是在运行时进行的。

声明动态类型的语法是 -

dynamic <variable_name> = value;

例如,

dynamic d = 20;

动态类型与对象类型类似,除了对象类型变量的类型检查在编译时进行,而动态类型变量的类型检查在运行时进行。

字符串类型

String Type允许您将任何字符串值分配给变量。 字符串类型是System.String类的别名。 它源自对象类型。 可以使用两种形式的字符串文字来指定字符串类型的值:quoted和@quoted。

例如,

String str = "IOWIKI";

@quoted字符串文字如下所示 -

@"IOWIKI";

用户定义的引用类型是:class,interface或delegate。 我们将在后面的章节中讨论这些类型。

指针类型

指针类型变量存储另一种类型的内存地址。 C#中的指针与C或C ++中的指针具有相同的功能。

声明指针类型的语法是 -

type* identifier;

例如,

char* cptr;
int* iptr;

我们将在“不安全代码”一章中讨论指针类型。

C# - Type Conversion

类型转换正在将一种类型的数据转换为另一种类型。 它也被称为类型转换。 在C#中,类型转换有两种形式 -

  • Implicit type conversion - 这些转换由C#以类型安全的方式执行。 例如,是从较小到较大的整数类型的转换以及从派生类到基类的转换。

  • Explicit type conversion - 这些转换由用户使用预定义函数Explicit type conversion完成。 显式转换需要强制转换运算符。

以下示例显示了显式类型转换 -

using System;
namespace TypeConversionApplication {
   class ExplicitConversion {
      static void Main(string[] args) {
         double d = 5673.74; 
         int i;
         // cast double to int.
         i = (int)d;
         Console.WriteLine(i);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

5673

C#类型转换方法

C#提供以下内置类型转换方法 -

Sr.No. 方法和描述
1

ToBoolean

尽可能将类型转换为布尔值。

2

ToByte

将类型转换为字节。

3

ToChar

尽可能将类型转换为单个Unicode字符。

4

ToDateTime

将类型(整数或字符串类型)转换为日期时间结构。

5

ToDecimal

将浮点或整数类型转换为十进制类型。

6

ToDouble

将类型转换为double类型。

7

ToInt16

将类型转换为16位整数。

8

ToInt32

将类型转换为32位整数。

9

ToInt64

将类型转换为64位整数。

10

ToSbyte

将类型转换为带符号的字节类型。

11

ToSingle

将类型转换为小浮点数。

12

ToString

将类型转换为字符串。

13

ToType

将类型转换为指定的类型。

14

ToUInt16

将类型转换为unsigned int类型。

15

ToUInt32

将类型转换为无符号长整型。

16

ToUInt64

将类型转换为无符号大整数。

以下示例将各种值类型转换为字符串类型 -

using System;
namespace TypeConversionApplication {
   class StringConversion {
      static void Main(string[] args) {
         int i = 75;
         float f = 53.005f;
         double d = 2345.7652;
         bool b = true;
         Console.WriteLine(i.ToString());
         Console.WriteLine(f.ToString());
         Console.WriteLine(d.ToString());
         Console.WriteLine(b.ToString());
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

75
53.005
2345.7652
True

C# - Variables

变量只不过是我们的程序可以操作的存储区域的名称。 C#中的每个变量都有一个特定的类型,它确定变量内存的大小和布局,可以存储在该内存中的值的范围以及可以应用于该变量的操作集。

C#中提供的基本值类型可分为 -

类型
Integral types sbyte,byte,short,ushort,int,uint,long,ulong和char
Floating point typesfloat and double
Decimal typesdecimal
Boolean types 分配的真或假值
Nullable types 可以为空的数据类型

C#还允许定义变量的其他值类型,例如enum和类的变量的引用类型,我们将在后续章节中介绍。

定义变量

C#中变量定义的语法是 -

<data_type> <variable_list>;

这里,data_type必须是有效的C#数据类型,包括char,int,float,double或任何用户定义的数据类型,variable_list可以包含一个或多个用逗号分隔的标识符名称。

这里显示了一些有效的变量定义 -

int i, j, k;
char c, ch;
float f, salary;
double d;

您可以在定义时将变量初始化为 -

int i = 100;

初始化变量

变量初始化(赋值),等号后跟常量表达式。 初始化的一般形式是 -

variable_name = value;

变量可以在其声明中初始化。 初始化程序由等号后跟常量表达式组成 -

<data_type> <variable_name> = value;

一些例子是 -

int d = 3, f = 5;    /* initializing d and f. */
byte z = 22;         /* initializes z. */
double pi = 3.14159; /* declares an approximation of pi. */
char x = 'x';        /* the variable x has the value 'x'. */

正确初始化变量是一种很好的编程习惯,否则程序可能会产生意外的结果。

以下示例使用各种类型的变量 -

using System;
namespace VariableDefinition {
   class Program {
      static void Main(string[] args) {
         short a;
         int b ;
         double c;
         /* actual initialization */
         a = 10;
         b = 20;
         c = a + b;
         Console.WriteLine("a = {0}, b = {1}, c = {2}", a, b, c);
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

a = 10, b = 20, c = 30

接受用户的值

System命名空间中的Console类提供了一个函数ReadLine()用于接受来自用户的输入并将其存储到变量中。

例如,

int num;
num = Convert.ToInt32(Console.ReadLine());

Convert.ToInt32()函数将用户输入的数据转换为int数据类型,因为Console.ReadLine()接受字符串格式的数据。

C#中的左值和右值表达式

C#中有两种表达式 -

  • lvalue - 作为lvalue的表达式可能显示为赋值的左侧或右侧。

  • rvalue - 作为rvalue的表达式可能出现在赋值的右侧但不是左侧。

变量是左值,因此它们可能出现在赋值的左侧。 数字文字是右值,因此它们可能不会被分配,也不能出现在左侧。 以下是有效的C#声明 -

int g = 20;

但是以下不是有效的语句,会产生编译时错误 -

10 = 20;

C# - Constants and Literals

常量指的是程序在执行期间不会改变的固定值。 这些固定值也称为文字。 常量可以是任何基本数据类型,如整数常量,浮点常量,字符常量或字符串文字。 还有枚举常量。

常量被视为常规变量,除了它们的值在定义后无法修改。

整型常量 (Integer Literals)

整数文字可以是十进制或十六进制常量。 前缀指定基数或基数:十六进制为0x或0X,十进制没有前缀ID。

整数文字也可以有一个后缀,它是U和L的组合,分别对于unsigned和long。 后缀可以是大写或小写,可以按任何顺序排列。

以下是整数文字的一些示例 -

212         /* Legal */
215u        /* Legal */
0xFeeL      /* Legal */

以下是各种类型的整数文字的其他示例 -

85         /* decimal */
0x4b       /* hexadecimal */
30         /* int */
30u        /* unsigned int */
30l        /* long */
30ul       /* unsigned long */

浮点型常量 (Floating-point Literals)

浮点文字有一个整数部分,一个小数点,一个小数部分和一个指数部分。 您可以以十进制形式或指数形式表示浮点文字。

以下是浮点文字的一些示例 -

3.14159       /* Legal */
314159E-5F    /* Legal */
510E          /* Illegal: incomplete exponent */
210f          /* Illegal: no decimal or exponent */
.e55          /* Illegal: missing integer or fraction */

在以十进制形式表示时,您必须包括小数点,指数或两者; 当使用指数形式表示时,您必须包括整数部分,小数部分或两者。 带符号的指数由e或E引入。

字符常量

字符文字用单引号括起来。 例如,'x'可以存储在char类型的简单变量中。 字符文字可以是普通字符(例如“x”),转义序列(例如“\ t”)或通用字符(例如“\ u02C0”)。

C#中有一些字符,前面是反斜杠。 它们具有特殊含义,用于表示换行符(\ n)或制表符(\ t)。 这里是一些这样的转义序列代码的列表 -

逃脱序列 含义
\\ \字符
\' ' character(字符)
\" " character(字符)
\? ? 字符
\aAlert or bell
\bBackspace
\fForm feed
\nNewline
\rCarriage return
\t 水平标签
\v 垂直标签
\xhh。 。 。 十六进制数字的一个或多个数字

以下是显示少数转义序列字符的示例 -

using System;
namespace EscapeChar {
   class Program {
      static void Main(string[] args) {
         Console.WriteLine("Hello\tWorld\n\n");
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Hello   World

字符串常量 (String Literals)

字符串文字或常量用双引号“”或@“”括起来。 字符串包含与字符文字类似的字符:普通字符,转义序列和通用字符。

您可以使用字符串文字将长行分成多行,并使用空格分隔部分。

以下是字符串文字的一些示例。 所有三种形式都是相同的字符串。

"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
@"hello dear"

定义常量

使用const关键字定义const 。 定义常量的语法是 -

const <data_type> <constant_name> = value;

以下程序演示了如何在程序中定义和使用常量 -

using System;
namespace DeclaringConstants {
    class Program {
        static void Main(string[] args) {
            const double pi = 3.14159;   
            // constant declaration 
            double r;
            Console.WriteLine("Enter Radius: ");
            r = Convert.ToDouble(Console.ReadLine());
            double areaCircle = pi * r * r;
            Console.WriteLine("Radius: {0}, Area: {1}", r, areaCircle);
            Console.ReadLine();
        }
    }
}

编译并执行上述代码时,会产生以下结果 -

Enter Radius: 
3
Radius: 3, Area: 28.27431

C# - Operators

运算符是一个符号,告诉编译器执行特定的数学或逻辑操作。 C#拥有丰富的内置运算符集,并提供以下类型的运算符 -

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 按位运算符
  • 分配运算符
  • 其它运算符

本教程逐个解释算术,关系,逻辑,按位,赋值和其他运算符。

算术运算符 (Arithmetic Operators)

下表显示了C#支持的所有算术运算符。 假设变量A保持10,变量B保持20然后 -

显示示例

操作者 描述
+ 添加两个操作数 A + B = 30
- 从第一个减去第二个操作数 A - B = -10
* 将两个操作数相乘 A * B = 200
/Divides numerator by de-numerator B/A = 2
% 模数运算符和整数除法后的余数 B%A = 0
++ 递增运算符将整数值增加1 A ++ = 11
-- 递减运算符将整数值减1 A-- = 9

关系运算符 (Relational Operators)

下表显示了C#支持的所有关系运算符。 假设变量A保持10,变量B保持20,则 -

显示示例

操作者 描述
== 检查两个操作数的值是否相等,如果是,则条件变为真。 (A == B)不是真的。
!= 检查两个操作数的值是否相等,如果值不相等则条件变为真。 (A!= B)是真的。
> 检查左操作数的值是否大于右操作数的值,如果是,则条件变为真。 (A> B)不是真的。
< 检查左操作数的值是否小于右操作数的值,如果是,则条件变为真。 (A < B) 为真
>= 检查左操作数的值是否大于或等于右操作数的值,如果是,则条件变为真。 (A> = B)不是真的。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是,则条件变为真。 (A <= B)是真的。

逻辑运算符 (Logical Operators)

下表显示了C#支持的所有逻辑运算符。 假设变量A保持布尔值true,变量B保持布尔值false,则 -

显示示例

操作者 描述
&& 称为逻辑AND运算符。 如果两个操作数都不为零,则条件成立。 (A && B)是假的。
|| 称为逻辑OR运算符。 如果两个操作数中的任何一个不为零,则条件变为真。 (A || B)是真的。
! 称为逻辑非运算符。 用于反转其操作数的逻辑状态。 如果条件为真,则Logical NOT运算符将为false。 !(A && B)是真的。

按位运算符 (Bitwise Operators)

按位运算符处理位并执行逐位运算。 &,|和^的真值表如下 -

p q p&q p | q p ^ q
00000
01011
11110
10011

假设A = 60; 和B = 13; 那么在二进制格式中它们如下 -

A = 0011 1100

B = 0000 1101

-------------------

A&B = 0000 1100

A | B = 0011 1101

A ^ B = 0011 0001

~A = 1100 0011

C#支持的Bitwise运算符如下表所示。 假设变量A保持60,变量B保持13,则 -

显示示例

操作者 描述
& 如果二进制AND运算符存在于两个操作数中,则它会将结果复制到结果中。 (A&B)= 12,即0000 1100
| 二进制OR运算符如果存在于任一操作数中,则复制一位。 (A | B)= 61,即0011 1101
^ 二进制异或运算符如果在一个操作数中设置但不在两个操作数中设置,则复制该位。 (A ^ B)= 49,即0011 0001
~ 二元一元补语运算符是一元的,具有“翻转”位的效果。 (~A)= 61,由于带符号的二进制数,它是2的补码中的1100 0011。
<< 二进制左移运算符。 左操作数值向左移动右操作数指定的位数。 A << 2 = 240,即1111 0000
>> 二进制右移运算符。 左操作数值向右移动右操作数指定的位数。 A >> 2 = 15,即0000 1111

赋值操作符 (Assignment Operators)

C#支持以下赋值运算符 -

显示示例

操作者 描述
= 简单赋值运算符,将右侧操作数的值分配给左侧操作数 C = A + B将A + B的值分配给C
+= 添加AND赋值运算符,它将右操作数添加到左操作数并将结果赋给左操作数 C + = A等于C = C + A.
-= 减去AND赋值运算符,它从左操作数中减去右操作数,并将结果赋给左操作数 C - = A相当于C = C - A.
*= 乘以AND赋值运算符,它将右操作数与左操作数相乘,并将结果赋值给左操作数 C * = A等于C = C * A.
/= 除法AND赋值运算符,它将左操作数除以右操作数,并将结果赋值给左操作数 C/= A相当于C = C/A.
%= 模数AND赋值运算符,使用两个操作数获取模数,并将结果赋给左操作数 C%= A等于C = C%A
<<= 左移AND赋值运算符 C << = 2与C = C << 2相同
>>= 右移AND赋值运算符 C >> = 2与C = C >> 2相同
&= 按位AND赋值运算符 C&= 2与C = C&2相同
^= 按位异或和赋值运算符 C ^ = 2与C = C ^ 2相同
|= 按位包含OR和赋值运算符 C | = 2与C = C |相同 2

混合操作符 (Miscellaneous Operators)

还有其他一些重要的运算符,包括sizeof, typeof? : ? :由C#支持。

显示示例

操作者 描述
sizeof() 返回数据类型的大小。 sizeof(int), returns 4.
typeof() 返回类的类型。 typeof(StreamReader);
& 返回变量的地址。 &一个; 返回变量的实际地址。
*Pointer to a variable. *一个; 为变量创建名为“a”的指针。
? : 条件表达式 如果条件为真? 然后是值X:否则为Y值
is 确定对象是否属于某种类型。 如果(福特是汽车)//检查福特是否是汽车类的对象。
as 如果演员表失败,则不会引发异常。 Object obj = new StringReader(“Hello”);

StringReader r = obj as StringReader;

C#中的运算符优先级

运算符优先级确定表达式中的术语分组。 这会影响表达式的评估。 某些运算符的优先级高于其他运算符; 例如,乘法运算符的优先级高于加法运算符。

例如x = 7 + 3 * 2; 这里,x被赋值为13,而不是20,因为operator *的优先级高于+,因此第一次评估发生在3 * 2,然后将7添加到其中。

此处,具有最高优先级的运算符显示在表的顶部,具有最低优先级的运算符显示在底部。 在表达式中,首先计算更高优先级的运算符。

显示示例

类别 操作者 关联性
Postfix ()[] - >。 ++ - - 左到右
Unary + - ! 〜++ - - (类型)*&sizeof 右到左
Multiplicative * /% 左到右
Additive + - 左到右
Shift << >> 左到右
Relational << => = 左到右
Equality ==!= 左到右
Bitwise AND& 左到右
Bitwise XOR ^ 左到右
Bitwise OR | 左到右
Logical AND && 左到右
Logical OR || 左到右
Conditional?: 右到左
Assignment = + = - = * =/=%= >> = << =&= ^ = | = 右到左
Comma, 左到右

C# - Decision Making

决策结构要求程序员指定一个或多个要由程序评估或测试的条件,以及在条件被确定为真时要执行的语句,以及可选的,如果条件要执行的其他语句被认定是假的。

以下是大多数编程语言中常见决策结构的一般形式 -

C#中的决策声明

C#提供以下类型的决策制定声明。 单击以下链接以检查其详细信息。

Sr.No. 声明和说明
1 if 语句

if statement由布尔表达式后跟一个或多个语句组成。

2 if...else 语句

if statement后面可以跟一个可选的else statement ,该else statement在布尔表达式为false时执行。

3 嵌套if语句

您可以在另一个ifelse if语句中使用ifelse if语句。

4 switch 语句

switch语句允许测试变量与值列表的相等性。

5 嵌套的switch语句

您可以在另一个switch语句中使用一个switch语句。

(The ? : Operator)

我们覆盖了conditional operator ? : conditional operator ? :在前一章中可以用来替换if...else语句。 它有以下一般形式 -

Exp1 ? Exp2 : Exp3;

Exp1,Exp2和Exp3是表达式。 注意结肠的使用和放置。

一个值? 表达式确定如下:评估Exp1。 如果是,那么Exp2会被评估并成为整个值吗? 表达。 如果Exp1为false,则计算Exp3,其值将成为表达式的值。

C# - Loops

当您需要多次执行代码块时,可能会出现这种情况。 通常,语句按顺序执行:首先执行函数中的第一个语句,然后执行第二个语句,依此类推。

编程语言提供各种控制结构,允许更复杂的执行路径。

循环语句允许我们多次执行语句或一组语句,以下是大多数编程语言中循环语句的一般说法 -

循环架构

C#提供以下类型的循环来处理循环要求。 单击以下链接以检查其详细信息。

Sr.No. 循环类型和描述
1 while 循环

当给定条件为真时,它重复一个陈述或一组陈述。 它在执行循环体之前测试条件。

2 for循环

它多次执行一系列语句,并缩写管理循环变量的代码。

3 做... while循环

它类似于while语句,除了它测试循环体末尾的条件

4 嵌套循环

您可以在任何其他循环中使用一个或多个循环,而for或do..while循环。

循环控制语句 (Loop Control Statements)

循环控制语句将执行从其正常序列更改。 当执行离开作用域时,将销毁在该作用域中创建的所有自动对象。

C#提供以下控制语句。 单击以下链接以查看其详细信息。

Sr.No. 控制声明和描述
1 break statement

终止loopswitch语句,并在循环或切换后立即将执行转移到语句。

2 continue statement

导致循环跳过其身体的其余部分,并在重复之前立即重新测试其状态。

无限循环

如果条件永远不会变为假,则循环变为无限循环。 for循环传统上用于此目的。 由于不需要构成for循环的三个表达式,因此可以通过将条件表达式留空来创建无限循环。

例子 (Example)

using System;
namespace Loops {
   class Program {
      static void Main(string[] args) {
         for (; ; ) {
            Console.WriteLine("Hey! I am Trapped");
         }
      }
   }
} 

当条件表达式不存在时,假定为真。 您可能有一个初始化和增量表达式,但程序员更常使用for(;;)构造来表示无限循环。

C# - Encapsulation

Encapsulation被定义为“将一个或多个项目封装在物理或逻辑包中的过程”。 在面向对象的编程方法中,封装阻止了对实现细节的访问。

抽象和封装是面向对象编程中的相关特征。 抽象允许使相关信息可见,封装使程序员能够implement the desired level of abstraction

使用access specifiers实现封装。 access specifier定义类成员的范围和可见性。 C#支持以下访问说明符 -

  • Public
  • Private
  • Protected
  • Internal
  • Protected internal

公共访问说明符

公共访问说明符允许类将其成员变量和成员函数公开给其他函数和对象。 可以从课外访问任何公共成员。

以下示例说明了这一点 -

using System;
namespace RectangleApplication {
   class Rectangle {
      //member variables
      public double length;
      public double width;
      public double GetArea() {
         return length * width;
      }
      public void Display() {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }//end class Rectangle
   class ExecuteRectangle {
      static void Main(string[] args) {
         Rectangle r = new Rectangle();
         r.length = 4.5;
         r.width = 3.5;
         r.Display();
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Length: 4.5
Width: 3.5
Area: 15.75

在前面的示例中,成员变量length和width被声明为public ,因此可以使用名为r的Rectangle类的实例从函数Main()访问它们。

成员函数Display()GetArea()也可以直接访问这些变量,而无需使用该类的任何实例。

成员函数Display()也被声明为public ,因此也可以使用名为r的Rectangle类的实例从Main()访问它。

私人访问说明符

私有访问说明符允许类从其他函数和对象隐藏其成员变量和成员函数。 只有同一个类的函数才能访问其私有成员。 即使是类的实例也无法访问其私有成员。

以下示例说明了这一点 -

using System;
namespace RectangleApplication {
   class Rectangle {
      //member variables
      private double length;
      private double width;
      public void Acceptdetails() {
         Console.WriteLine("Enter Length: ");
         length = Convert.ToDouble(Console.ReadLine());
         Console.WriteLine("Enter Width: ");
         width = Convert.ToDouble(Console.ReadLine());
      }
      public double GetArea() {
         return length * width;
      }
      public void Display() {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }//end class Rectangle
   class ExecuteRectangle {
      static void Main(string[] args) {
         Rectangle r = new Rectangle();
         r.Acceptdetails();
         r.Display();
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Enter Length:
4.4
Enter Width:
3.3
Length: 4.4
Width: 3.3
Area: 14.52

在前面的示例中,成员变量length和width被声明为private ,因此无法从函数Main()访问它们。 成员函数AcceptDetails()Display()可以访问这些变量。 由于成员函数AcceptDetails()Display()被声明为public ,因此可以使用名为r的Rectangle类的实例从Main()访问它们。

受保护的访问说明符

受保护的访问说明符允许子类访问其基类的成员变量和成员函数。 这样它有助于实现继承。 我们将在继承章节中更详细地讨论这个问题。

内部访问说明符

内部访问说明符允许类将其成员变量和成员函数公开给当前程序集中的其他函数和对象。 换句话说,可以从定义成员的应用程序中定义的任何类或方法访问具有内部访问说明符的任何成员。

以下程序说明了这一点 -

using System;
namespace RectangleApplication {
   class Rectangle {
      //member variables
      internal double length;
      internal double width;
      double GetArea() {
         return length * width;
      }
      public void Display() {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }//end class Rectangle
   class ExecuteRectangle {
      static void Main(string[] args) {
         Rectangle r = new Rectangle();
         r.length = 4.5;
         r.width = 3.5;
         r.Display();
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Length: 4.5
Width: 3.5
Area: 15.75

在前面的示例中,请注意,成员函数GetArea()未使用任何访问说明符声明。 那么如果我们不提及任何类成员的默认访问说明符是什么? 这是private

受保护的内部访问说明符

受保护的内部访问说明符允许类从其他类对象和函数中隐藏其成员变量和成员函数,但同一应用程序中的子类除外。 在实现继承时也使用它。

C# - Methods

方法是一组一起执行任务的语句。 每个C#程序至少有一个类,其方法名为Main。

要使用方法,您需要 -

  • 定义方法
  • Call the method

在C#中定义方法

定义方法时,基本上声明其结构的元素。 在C#中定义方法的语法如下 -

<Access Specifier> <Return Type> <Method Name>(Parameter List) {
   Method Body
}

以下是方法的各种要素 -

  • Access Specifier - 这确定了来自另一个类的变量或方法的可见性。

  • Return type - 方法可以返回值。 返回类型是方法返回的值的数据类型。 如果方法未返回任何值,则返回类型为void

  • Method name - 方法名称是唯一标识符,区分大小写。 它不能与类中声明的任何其他标识符相同。

  • Parameter list - 括在括号中,参数用于传递和接收方法中的数据。 参数列表指的是方法的参数的类型,顺序和数量。 参数是可选的; 也就是说,方法可能不包含任何参数。

  • Method body - 包含完成所需活动所需的一组指令。

例子 (Example)

下面的代码片段显示了一个函数FindMax ,它接受两个整数值并返回两者中较大的一个。 它具有公共访问说明符,因此可以使用类的实例从类外部访问它。

class NumberManipulator {
   public int FindMax(int num1, int num2) {
      /* local variable declaration */
      int result;
      if (num1 > num2)
         result = num1;
      else
         result = num2;
      return result;
   }
   ...
}

在C#中调用方法

您可以使用方法名称调用方法。 以下示例说明了这一点 -

using System;
namespace CalculatorApplication {
   class NumberManipulator {
      public int FindMax(int num1, int num2) {
         /* local variable declaration */
         int result;
         if (num1 > num2)
            result = num1;
         else
            result = num2;
         return result;
      }
      static void Main(string[] args) {
         /* local variable definition */
         int a = 100;
         int b = 200;
         int ret;
         NumberManipulator n = new NumberManipulator();
         //calling the FindMax method
         ret = n.FindMax(a, b);
         Console.WriteLine("Max value is : {0}", ret );
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Max value is : 200

您还可以使用类的实例从其他类调用公共方法。 例如, FindMax方法属于NumberManipulator类,您可以从另一个类Test调用它。

using System;
namespace CalculatorApplication {
   class NumberManipulator {
      public int FindMax(int num1, int num2) {
         /* local variable declaration */
         int result;
         if(num1 > num2)
            result = num1;
         else
            result = num2;
         return result;
      }
   }
   class Test {
      static void Main(string[] args) {
         /* local variable definition */
         int a = 100;
         int b = 200;
         int ret;
         NumberManipulator n = new NumberManipulator();
         //calling the FindMax method
         ret = n.FindMax(a, b);
         Console.WriteLine("Max value is : {0}", ret );
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Max value is : 200

递归方法调用

一种方法可以调用自己。 这称为recursion 。 以下是使用递归函数计算给定数字的阶乘的示例 -

using System;
namespace CalculatorApplication {
   class NumberManipulator {
      public int factorial(int num) {
         /* local variable declaration */
         int result;
         if (num == 1) {
            return 1;
         }
         else {
            result = factorial(num - 1) * num;
            return result;
         }
      }
      static void Main(string[] args) {
         NumberManipulator n = new NumberManipulator();
         //calling the factorial method {0}", n.factorial(6));
         Console.WriteLine("Factorial of 7 is : {0}", n.factorial(7));
         Console.WriteLine("Factorial of 8 is : {0}", n.factorial(8));
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Factorial of 6 is: 720
Factorial of 7 is: 5040
Factorial of 8 is: 40320

将参数传递给方法

调用带参数的方法时,需要将参数传递给方法。 参数可以通过三种方式传递给方法 -

Sr.No. 机制和描述
1 值参数

此方法将参数的实际值复制到函数的形式参数中。 在这种情况下,对函数内部参数所做的更改不会对参数产生影响。

2 参考参数

此方法将对参数的内存位置的引用复制到形式参数中。 这意味着对参数所做的更改会影响参数。

3 输出参数

此方法有助于返回多个值。

C# - Nullables

C#提供了一种特殊的数据类型,可以为nullable类型,您可以为其分配正常的值范围以及空值。

例如,您可以存储-2,147,483,648到2,147,483,647之间的任何值,或者在Nullable 变量中存储null。 同样,您可以在Nullable 变量中指定true,false或null。 声明nullable类型的语法如下 -

< data_type> ? <variable_name> = null;

以下示例演示了可空数据类型的使用 -

using System;
namespace CalculatorApplication {
   class NullablesAtShow {
      static void Main(string[] args) {
         int? num1 = null;
         int? num2 = 45;
         double? num3 = new double?();
         double? num4 = 3.14157;
         bool? boolval = new bool?();
         // display the values
         Console.WriteLine("Nullables at Show: {0}, {1}, {2}, {3}", num1, num2, num3, num4);
         Console.WriteLine("A Nullable boolean value: {0}", boolval);
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Nullables at Show: , 45,  , 3.14157
A Nullable boolean value:

Null Coalescing运算符(??)

null合并运算符与可空值类型和引用类型一起使用。 它用于将操作数转换为另一个可空(或非)值类型操作数的类型,其中可以进行隐式转换。

如果第一个操作数的值为null,则运算符返回第二个操作数的值,否则返回第一个操作数的值。 以下示例解释了这一点 -

using System;
namespace CalculatorApplication {
   class NullablesAtShow {
      static void Main(string[] args) {
         double? num1 = null;
         double? num2 = 3.14157;
         double num3;
         num3 = num1 ?? 5.34;      
         Console.WriteLine(" Value of num3: {0}", num3);
         num3 = num2 ?? 5.34;
         Console.WriteLine(" Value of num3: {0}", num3);
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Value of num3: 5.34
Value of num3: 3.14157

C# - Arrays

数组存储相同类型的固定大小的顺序元素集合。 数组用于存储数据集合,但将数组视为存储在连续内存位置的相同类型变量的集合通常更有用。

您可以声明一个数组变量(例如数字)并使用数字[0],数字[1]和...,数字[99]来表示单个变量,例如number0,number1,...和number99,而不是声明单个变量。个别变数。 索引访问数组中的特定元素。

所有阵列都包含连续的内存位置。 最低地址对应于第一个元素,最高地址对应于最后一个元素。

C#中的数组

声明数组 (Declaring Arrays)

要在C#中声明数组,可以使用以下语法 -

datatype[] arrayName;

Where,

  • datatype用于指定数组中元素的类型。

  • [ ]指定数组的等级。 rank指定数组的大小。

  • arrayName指定数组的名称。

例如,

double[] balance;

初始化数组

声明数组不会初始化内存中的数组。 初始化数组变量时,可以为数组赋值。

Array是引用类型,因此您需要使用new关键字来创建数组的实例。 例如,

double[] balance = new double[10];

将值分配给数组

您可以使用索引号为单个数组元素赋值,如 -

double[] balance = new double[10];
balance[0] = 4500.0;

您可以在声明时为数组赋值,如图所示 -

double[] balance = { 2340.0, 4523.69, 3421.0};

您还可以创建和初始化数组,如图所示 -

int [] marks = new int[5]  { 99,  98, 92, 97, 95};

你也可以省略数组的大小,如图所示 -

int [] marks = new int[]  { 99,  98, 92, 97, 95};

您可以将数组变量复制到另一个目标数组变量中。 在这种情况下,目标和源都指向相同的内存位置 -

int [] marks = new int[]  { 99,  98, 92, 97, 95};
int[] score = marks;

创建数组时,C#编译器会根据数组类型隐式地将每个数组元素初始化为默认值。 例如,对于int数组,所有元素都初始化为0。

访问数组元素 (Accessing Array Elements)

通过索引数组名称来访问元素。 这是通过将元素的索引放在数组名称后面的方括号中来完成的。 例如,

double salary = balance[9];

以下示例演示了上述概念声明,赋值和访问数组 -

using System;
namespace ArrayApplication {
   class MyArray {
      static void Main(string[] args) {
         int []  n = new int[10]; /* n is an array of 10 integers */
         int i,j;
         /* initialize elements of array n */
         for ( i = 0; i < 10; i++ ) {
            n[ i ] = i + 100;
         }
         /* output each array element's value */
         for (j = 0; j < 10; j++ ) {
            Console.WriteLine("Element[{0}] = {1}", j, n[j]);
         }
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

使用foreach循环

在前面的示例中,我们使用for循环来访问每个数组元素。 您还可以使用foreach语句迭代数组。

using System;
namespace ArrayApplication {
   class MyArray {
      static void Main(string[] args) {
         int []  n = new int[10]; /* n is an array of 10 integers */
         /* initialize elements of array n */
         for ( int i = 0; i < 10; i++ ) {
            n[i] = i + 100;
         }
         /* output each array element's value */
         foreach (int j in n ) {
            int i = j-100;
            Console.WriteLine("Element[{0}] = {1}", i, j);
         }
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

C#数组

以下几个与数组相关的重要概念对C#程序员来说应该是清楚的 -

Sr.No. 概念与描述
1 多维数组

C#支持多维数组。 多维数组的最简单形式是二维数组。

2 Jagged arrays

C#支持多维数组,这是数组的数组。

3 将数组传递给函数

您可以通过指定不带索引的数组名称来向函数传递指向数组的指针。

4 Param数组

这用于将未知数量的参数传递给函数。

5 数组类

在System命名空间中定义,它是所有数组的基类,并提供用于处理数组的各种属性和方法。

C# - Strings

在C#中,您可以使用字符串作为字符数组。但是,更常见的做法是使用string关键字来声明字符串变量。 string关键字是System.String类的别名。

创建一个String对象

您可以使用以下方法之一创建字符串对象 -

  • 通过将字符串文字分配给String变量

  • 通过使用String类构造函数

  • 通过使用字符串连接运算符(+)

  • 通过检索属性或调用返回字符串的方法

  • 通过调用格式化方法将值或对象转换为其字符串表示形式

以下示例演示了这一点 -

using System;
namespace StringApplication {
   class Program {
      static void Main(string[] args) {
         //from string literal and string concatenation
         string fname, lname;
         fname = "Rowan";
         lname = "Atkinson";
         char []letters= { 'H', 'e', 'l', 'l','o' };
         string [] sarray={ "Hello", "From", "Tutorials", "Point" };
         string fullname = fname + lname;
         Console.WriteLine("Full Name: {0}", fullname);
         //by using string constructor { 'H', 'e', 'l', 'l','o' };
         string greetings = new string(letters);
         Console.WriteLine("Greetings: {0}", greetings);
         //methods returning string { "Hello", "From", "Tutorials", "Point" };
         string message = String.Join(" ", sarray);
         Console.WriteLine("Message: {0}", message);
         //formatting method to convert a value
         DateTime waiting = new DateTime(2012, 10, 10, 17, 58, 1);
         string chat = String.Format("Message sent at {0:t} on {0:D}", waiting);
         Console.WriteLine("Message: {0}", chat);
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Full Name: RowanAtkinson
Greetings: Hello
Message: Hello From IOWIKI
Message: Message sent at 5:58 PM on Wednesday, October 10, 2012

字符串类的属性

String类具有以下两个属性 -

Sr.No. 财产和描述
1

Chars

获取当前String对象中指定位置的Char对象。

2

Length

获取当前String对象中的字符数。

String类的方法

String类有许多方法可以帮助您处理字符串对象。 下表提供了一些最常用的方法 -

Sr.No. 方法和描述
1

public static int Compare(string strA, string strB)

比较两个指定的字符串对象,并返回一个整数,指示它们在排序顺序中的相对位置。

2

public static int Compare(string strA, string strB, bool ignoreCase )

比较两个指定的字符串对象,并返回一个整数,指示它们在排序顺序中的相对位置。 但是,如果Boolean参数为true,则忽略大小写。

3

public static string Concat(string str0, string str1)

连接两个字符串对象。

4

public static string Concat(string str0, string str1, string str2)

连接三个字符串对象。

5

public static string Concat(string str0, string str1, string str2, string str3)

连接四个字符串对象。

6

public bool Contains(string value)

返回一个值,该值指示指定的String对象是否出现在此字符串中。

7

public static string Copy(string str)

创建一个与指定字符串具有相同值的新String对象。

8

public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)

将指定数量的字符从String对象的指定位置复制到Unicode字符数组中的指定位置。

9

public bool EndsWith(string value)

确定字符串对象的结尾是否与指定的字符串匹配。

10

public bool Equals(string value)

确定当前String对象和指定的String对象是否具有相同的值。

11

public static bool Equals(string a, string b)

确定两个指定的String对象是否具有相同的值。

12

public static string Format(string format, Object arg0)

使用指定对象的字符串表示形式替换指定字符串中的一个或多个格式项。

13

public int IndexOf(char value)

返回当前字符串中第一次出现的指定Unicode字符的从零开始的索引。

14

public int IndexOf(string value)

返回此实例中第一次出现的指定字符串的从零开始的索引。

15

public int IndexOf(char value, int startIndex)

返回此字符串中第一次出现的指定Unicode字符的从零开始的索引,从指定的字符位置开始搜索。

16

public int IndexOf(string value, int startIndex)

返回此实例中第一次出现的指定字符串的从零开始的索引,从指定的字符位置开始搜索。

17

public int IndexOfAny(char[] anyOf)

返回指定Unicode字符数组中任何字符的此实例中第一次出现的从零开始的索引。

18

public int IndexOfAny(char[] anyOf, int startIndex)

返回指定Unicode字符数组中任何字符的此实例中第一次出现的从零开始的索引,从指定字符位置开始搜索。

19

public string Insert(int startIndex, string value)

返回一个新字符串,其中在当前字符串对象的指定索引位置插入指定的字符串。

20

public static bool IsNullOrEmpty(string value)

指示指定的字符串是null还是空字符串。

21

public static string Join(string separator, params string[] value)

使用每个元素之间的指定分隔符连接字符串数组的所有元素。

22

public static string Join(string separator, string[] value, int startIndex, int count)

使用每个元素之间的指定分隔符连接字符串数组的指定元素。

23

public int LastIndexOf(char value)

返回当前字符串对象中最后一次出现的指定Unicode字符的从零开始的索引位置。

24

public int LastIndexOf(string value)

返回当前字符串对象中最后一次出现的指定字符串的从零开始的索引位置。

25

public string Remove(int startIndex)

从当前实例中删除所有字符,从指定位置开始并继续到最后一个位置,然后返回字符串。

26

public string Remove(int startIndex, int count)

从指定位置开始删除当前字符串中指定数量的字符并返回该字符串。

27

public string Replace(char oldChar, char newChar)

使用指定的Unicode字符替换当前字符串对象中所有出现的指定Unicode字符,并返回新字符串。

28

public string Replace(string oldValue, string newValue)

使用指定的字符串替换当前字符串对象中所有出现的指定字符串,并返回新字符串。

29

public string[] Split(params char[] separator)

返回一个字符串数组,该数组包含当前字符串对象中的子字符串,由指定的Unicode字符数组的元素分隔。

30

public string[] Split(char[] separator, int count)

返回一个字符串数组,该数组包含当前字符串对象中的子字符串,由指定的Unicode字符数组的元素分隔。 int参数指定要返回的最大子串数。

31

public bool StartsWith(string value)

确定此字符串实例的开头是否与指定的字符串匹配。

32

public char[] ToCharArray()

返回包含当前字符串对象中所有字符的Unicode字符数组。

33

public char[] ToCharArray(int startIndex, int length)

返回一个Unicode字符数组,其中包含当前字符串对象中的所有字符,从指定的索引开始直到指定的长度。

34

public string ToLower()

返回转换为小写的此字符串的副本。

35

public string ToUpper()

返回转换为大写的此字符串的副本。

36

public string Trim()

从当前String对象中删除所有前导和尾随空格字符。

您可以访问MSDN库以获取完整的方法列表和String类构造函数。

例子 (Examples)

以下示例演示了上面提到的一些方法 -

比较字符串

using System;
namespace StringApplication {
   class StringProg {
      static void Main(string[] args) {
         string str1 = "This is test";
         string str2 = "This is text";
         if (String.Compare(str1, str2) == 0) {
            Console.WriteLine(str1 + " and " + str2 +  " are equal.");
         } else {
            Console.WriteLine(str1 + " and " + str2 + " are not equal.");
         }
         Console.ReadKey() ;
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

This is test and This is text are not equal.

String包含String

using System;
namespace StringApplication {
   class StringProg {
      static void Main(string[] args) {
         string str = "This is test";
         if (str.Contains("test")) {
            Console.WriteLine("The sequence 'test' was found.");
         }
         Console.ReadKey() ;
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

The sequence 'test' was found.

获得子串

using System;
namespace StringApplication {
   class StringProg {
      static void Main(string[] args) {
         string str = "Last night I dreamt of San Pedro";
         Console.WriteLine(str);
         string substr = str.Substring(23);
         Console.WriteLine(substr);
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

San Pedro

加入字符串

using System;
namespace StringApplication {
   class StringProg {
      static void Main(string[] args) {
         string[] starray = new string[]{"Down the way nights are dark",
            "And the sun shines daily on the mountain top",
            "I took a trip on a sailing ship",
            "And when I reached Jamaica",
            "I made a stop"};
         string str = String.Join("\n", starray);
         Console.WriteLine(str);
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Down the way nights are dark
And the sun shines daily on the mountain top
I took a trip on a sailing ship
And when I reached Jamaica
I made a stop

C# - Structures

在C#中,结构是值类型数据类型。 它可以帮助您使单个变量保存各种数据类型的相关数据。 struct关键字用于创建结构。

结构用于表示记录。 假设您想要在图书馆中跟踪您的图书。 您可能希望跟踪每本书的以下属性 -

  • Title
  • Author
  • Subject
  • Book ID

定义一个结构 (Defining a Structure)

要定义结构,必须使用struct语句。 struct语句定义一个新的数据类型,为您的程序提供多个成员。

例如,以下是您可以声明Book结构的方式 -

struct Books {
   public string title;
   public string author;
   public string subject;
   public int book_id;
};  

以下程序显示了该结构的使用 -

using System;
struct Books {
   public string title;
   public string author;
   public string subject;
   public int book_id;
};  
public class testStructure {
   public static void Main(string[] args) {
      Books Book1;   /* Declare Book1 of type Book */
      Books Book2;   /* Declare Book2 of type Book */
      /* book 1 specification */
      Book1.title = "C Programming";
      Book1.author = "Nuha Ali"; 
      Book1.subject = "C Programming Tutorial";
      Book1.book_id = 6495407;
      /* book 2 specification */
      Book2.title = "Telecom Billing";
      Book2.author = "Zara Ali";
      Book2.subject =  "Telecom Billing Tutorial";
      Book2.book_id = 6495700;
      /* print Book1 info */
      Console.WriteLine( "Book 1 title : {0}", Book1.title);
      Console.WriteLine("Book 1 author : {0}", Book1.author);
      Console.WriteLine("Book 1 subject : {0}", Book1.subject);
      Console.WriteLine("Book 1 book_id :{0}", Book1.book_id);
      /* print Book2 info */
      Console.WriteLine("Book 2 title : {0}", Book2.title);
      Console.WriteLine("Book 2 author : {0}", Book2.author);
      Console.WriteLine("Book 2 subject : {0}", Book2.subject);
      Console.WriteLine("Book 2 book_id : {0}", Book2.book_id);       
      Console.ReadKey();
   }
}

编译并执行上述代码时,会产生以下结果 -

Book 1 title : C Programming
Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700

C#结构的特点

您已经使用了名为Books的简单结构。 C#中的结构与传统的C或C ++中的结构完全不同。 C#结构具有以下功能 -

  • 结构可以包含方法,字段,索引器,属性,运算符方法和事件。

  • 结构可以有定义的构造函数,但不能有析构函数。 但是,您无法为结构定义默认构造函数。 默认构造函数是自动定义的,无法更改。

  • 与类不同,结构不能继承其他结构或类。

  • 结构不能用作其他结构或类的基础。

  • 结构可以实现一个或多个接口。

  • 不能将结构成员指定为抽象,虚拟或受保护。

  • 使用New运算符创建struct对象时,会创建它并调用相应的构造函数。 与类不同,可以在不使用New运算符的情况下实例化结构。

  • 如果未使用New运算符,则字段将保持未分配状态,并且在初始化所有字段之前无法使用该对象。

阶级与结构

类和结构具有以下基本差异 -

  • 类是引用类型,结构是值类型
  • 结构不支持继承
  • 结构不能有默认构造函数

根据上述讨论,让我们重写前面的例子 -

using System;
struct Books {
   private string title;
   private string author;
   private string subject;
   private int book_id;
   public void getValues(string t, string a, string s, int id) {
      title = t;
      author = a;
      subject = s;
      book_id = id;
   }
   public void display() {
      Console.WriteLine("Title : {0}", title);
      Console.WriteLine("Author : {0}", author);
      Console.WriteLine("Subject : {0}", subject);
      Console.WriteLine("Book_id :{0}", book_id);
   }
};  
public class testStructure {
   public static void Main(string[] args) {
      Books Book1 = new Books();   /* Declare Book1 of type Book */
      Books Book2 = new Books();   /* Declare Book2 of type Book */
      /* book 1 specification */
      Book1.getValues("C Programming",
      "Nuha Ali", "C Programming Tutorial",6495407);
      /* book 2 specification */
      Book2.getValues("Telecom Billing",
      "Zara Ali", "Telecom Billing Tutorial", 6495700);
      /* print Book1 info */
      Book1.display();
      /* print Book2 info */
      Book2.display(); 
      Console.ReadKey();
   }
}

编译并执行上述代码时,会产生以下结果 -

Title : C Programming
Author : Nuha Ali
Subject : C Programming Tutorial
Book_id : 6495407
Title : Telecom Billing
Author : Zara Ali
Subject : Telecom Billing Tutorial
Book_id : 6495700

C# - Enums

枚举是一组命名的整数常量。 使用enum关键字声明枚举类型。

C#枚举是值数据类型。 换句话说,枚举包含自己的值,不能继承或不能传递继承。

声明enum变量

声明枚举的一般语法是 -

enum <enum_name> {
   enumeration list 
};

Where,

  • enum_name指定枚举类型名称。

  • enumeration list是以逗号分隔的标识符列表。

枚举列表中的每个符号代表一个整数值,一个大于它之前的符号。 默认情况下,第一个枚举符号的值为0.例如 -

enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };

例子 (Example)

以下示例演示了枚举变量的使用 -

using System;
namespace EnumApplication {
   class EnumProgram {
      enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };
      static void Main(string[] args) {
         int WeekdayStart = (int)Days.Mon;
         int WeekdayEnd = (int)Days.Fri;
         Console.WriteLine("Monday: {0}", WeekdayStart);
         Console.WriteLine("Friday: {0}", WeekdayEnd);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Monday: 1
Friday: 5

C# - Classes

定义类时,可以为数据类型定义蓝图。 这实际上并没有定义任何数据,但它确实定义了类名的含义。 也就是说,该类的对象包括什么以及可以对该对象执行什么操作。 对象是类的实例。 构成类的方法和变量称为类的成员。

定义一个类

类定义以关键字class开头,后跟类名; 并且由一对花括号包围的类体。 以下是类定义的一般形式 -

<access specifier> class  class_name {
   // member variables
   <access specifier> <data type> variable1;
   <access specifier> <data type> variable2;
   ...
   <access specifier> <data type> variableN;
   // member methods
   <access specifier> <return type> method1(parameter_list) {
      // method body
   }
   <access specifier> <return type> method2(parameter_list) {
      // method body
   }
   ...
   <access specifier> <return type> methodN(parameter_list) {
      // method body
   }
}

注意 -

  • 访问说明符指定成员的访问规则以及类本身。 如果未提及,则类类型的默认访问说明符为internal 。 成员的默认访问权限是private

  • 数据类型指定变量的类型,返回类型指定方法返回的数据的数据类型(如果有)。

  • 要访问类成员,请使用点(。)运算符。

  • 点运算符将对象的名称与成员的名称相链接。

以下示例说明了目前讨论的概念 -

using System;
namespace BoxApplication {
    class Box {
       public double length;   // Length of a box
       public double breadth;  // Breadth of a box
       public double height;   // Height of a box
    }
    class Boxtester {
        static void Main(string[] args) {
            Box Box1 = new Box();   // Declare Box1 of type Box
            Box Box2 = new Box();   // Declare Box2 of type Box
            double volume = 0.0;    // Store the volume of a box here
            // box 1 specification
            Box1.height = 5.0;
            Box1.length = 6.0;
            Box1.breadth = 7.0;
            // box 2 specification
            Box2.height = 10.0;
            Box2.length = 12.0;
            Box2.breadth = 13.0;
            // volume of box 1
            volume = Box1.height * Box1.length * Box1.breadth;
            Console.WriteLine("Volume of Box1 : {0}",  volume);
            // volume of box 2
            volume = Box2.height * Box2.length * Box2.breadth;
            Console.WriteLine("Volume of Box2 : {0}", volume);
            Console.ReadKey();
        }
    }
}

编译并执行上述代码时,会产生以下结果 -

Volume of Box1 : 210
Volume of Box2 : 1560

成员函数和封装

类的成员函数是一个函数,它的定义或其原型在类定义中类似于任何其他变量。 它对其所属的类的任何对象进行操作,并且可以访问该对象的类的所有成员。

成员变量是对象的属性(从设计角度来看),它们保持私有以实现封装。 只能使用公共成员函数访问这些变量。

让我们在上面的概念中设置并获取类中不同类成员的值 -

using System;
namespace BoxApplication {
   class Box {
      private double length;   // Length of a box
      private double breadth;  // Breadth of a box
      private double height;   // Height of a box
      public void setLength( double len ) {
         length = len;
      }
      public void setBreadth( double bre ) {
         breadth = bre;
      }
      public void setHeight( double hei ) {
         height = hei;
      }
      public double getVolume() {
         return length * breadth * height;
      }
   }
   class Boxtester {
      static void Main(string[] args) {
         Box Box1 = new Box();   // Declare Box1 of type Box
         Box Box2 = new Box();
         double volume;
         // Declare Box2 of type Box
         // box 1 specification
         Box1.setLength(6.0);
         Box1.setBreadth(7.0);
         Box1.setHeight(5.0);
         // box 2 specification
         Box2.setLength(12.0);
         Box2.setBreadth(13.0);
         Box2.setHeight(10.0);
         // volume of box 1
         volume = Box1.getVolume();
         Console.WriteLine("Volume of Box1 : {0}" ,volume);
         // volume of box 2
         volume = Box2.getVolume();
         Console.WriteLine("Volume of Box2 : {0}", volume);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Volume of Box1 : 210
Volume of Box2 : 1560

C#构造函数

constructor是类的特殊成员函数,只要我们创建该类的新对象,就会执行该函数。

构造函数与类的名称完全相同,并且它没有任何返回类型。 下面的例子解释了构造函数的概念 -

using System;
namespace LineApplication {
   class Line {
      private double length;   // Length of a line
      public Line() {
         Console.WriteLine("Object is being created");
      }
      public void setLength( double len ) {
         length = len;
      }
      public double getLength() {
         return length;
      }
      static void Main(string[] args) {
         Line line = new Line();    
         // set line length
         line.setLength(6.0);
         Console.WriteLine("Length of line : {0}", line.getLength());
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Object is being created
Length of line : 6

default constructor函数没有任何参数,但如果需要,构造函数可以有参数。 这种构造函数称为parameterized constructors 。 此技术可帮助您在创建对象时为其分配初始值,如以下示例所示 -

using System;
namespace LineApplication {
   class Line {
      private double length;   // Length of a line
      public Line(double len) {  //Parameterized constructor
         Console.WriteLine("Object is being created, length = {0}", len);
         length = len;
      }
      public void setLength( double len ) {
         length = len;
      }
      public double getLength() {
         return length;
      }
      static void Main(string[] args) {
         Line line = new Line(10.0);
         Console.WriteLine("Length of line : {0}", line.getLength()); 
         // set line length
         line.setLength(6.0);
         Console.WriteLine("Length of line : {0}", line.getLength()); 
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Object is being created, length = 10
Length of line : 10
Length of line : 6

C#析构函数

destructor是类的特殊成员函数,只要其类的对象超出范围,就会执行该函数。 destructor与具有前缀波形符(〜)的类具有完全相同的名称,并且它既不能返回值也不能接受任何参数。

在退出程序之前,析构函数对于释放内存资源非常有用。 析构函数不能被继承或重载。

以下示例解释了析构函数的概念 -

using System;
namespace LineApplication {
   class Line {
      private double length;   // Length of a line
      public Line() {   // constructor
         Console.WriteLine("Object is being created");
      }
      ~Line() {   //destructor
         Console.WriteLine("Object is being deleted");
      }
      public void setLength( double len ) {
         length = len;
      }
      public double getLength() {
         return length;
      }
      static void Main(string[] args) {
         Line line = new Line();
         // set line length
         line.setLength(6.0);
         Console.WriteLine("Length of line : {0}", line.getLength());           
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Object is being created
Length of line : 6
Object is being deleted

C#类的静态成员

我们可以使用static关键字将类成员定义为static。 当我们将类的成员声明为static时,这意味着无论创建了多少个类的对象,都只有一个静态成员的副本。

关键字static表示对于类只存在一个成员实例。 静态变量用于定义常量,因为可以通过调用类来检索它们的值,而无需创建它的实例。 静态变量可以在成员函数或类定义之外初始化。 您还可以在类定义中初始化静态变量。

以下示例演示static variables的使用 -

using System;
namespace StaticVarApplication {
   class StaticVar {
      public static int num;
      public void count() {
         num++;
      }
      public int getNum() {
         return num;
      }
   }
   class StaticTester {
      static void Main(string[] args) {
         StaticVar s1 = new StaticVar();
         StaticVar s2 = new StaticVar();
         s1.count();
         s1.count();
         s1.count();
         s2.count();
         s2.count();
         s2.count();
         Console.WriteLine("Variable num for s1: {0}", s1.getNum());
         Console.WriteLine("Variable num for s2: {0}", s2.getNum());
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Variable num for s1: 6
Variable num for s2: 6

您还可以将member function声明为static 。 这些函数只能访问静态变量。 甚至在创建对象之前就存在静态函数。 以下示例演示static functions的使用 -

using System;
namespace StaticVarApplication {
   class StaticVar {
      public static int num;
      public void count() {
         num++;
      }
      public static int getNum() {
         return num;
      }
   }
   class StaticTester {
      static void Main(string[] args) {
         StaticVar s = new StaticVar();
         s.count();
         s.count();
         s.count();
         Console.WriteLine("Variable num: {0}", StaticVar.getNum());
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Variable num: 3

C# - Inheritance

面向对象编程中最重要的概念之一是继承。 继承允许我们根据另一个类定义一个类,这使得创建和维护应用程序变得更容易。 这也提供了重用代码功能并加快实现时间的机会。

在创建类时,程序员可以指定新类应该继承现有类的成员,而不是编写全新的数据成员和成员函数。 此现有类称为base类,新类称为derived类。

继承的想法实现了IS-A关系。 例如,哺乳动物IS A动物,狗IS-A哺乳动物,因此也是狗IS-A动物,等等。

基础和派生类

类可以从多个类或接口派生,这意味着它可以从多个基类或接口继承数据和函数。

C#中用于创建派生类的语法如下 -

<acess-specifier> class <base_class> {
   ...
}
class <derived_class> : <base_class> {
   ...
}

考虑一个基类Shape及其派生类Rectangle -

using System;
namespace InheritanceApplication {
   class Shape {
      public void setWidth(int w) {
         width = w;
      }
      public void setHeight(int h) {
         height = h;
      }
      protected int width;
      protected int height;
   }
   // Derived class
   class Rectangle: Shape {
      public int getArea() { 
         return (width * height); 
      }
   }
   class RectangleTester {
      static void Main(string[] args) {
         Rectangle Rect = new Rectangle();
         Rect.setWidth(5);
         Rect.setHeight(7);
         // Print the area of the object.
         Console.WriteLine("Total area: {0}",  Rect.getArea());
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Total area: 35

初始化基类

派生类继承基类成员变量和成员方法。 因此,应在创建子类之前创建超类对象。 您可以在成员初始化列表中提供超类初始化的说明。

以下程序演示了这一点 -

using System;
namespace RectangleApplication {
   class Rectangle {
      //member variables
      protected double length;
      protected double width;
      public Rectangle(double l, double w) {
         length = l;
         width = w;
      }
      public double GetArea() {
         return length * width;
      }
      public void Display() {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }//end class Rectangle  
   class Tabletop : Rectangle {
      private double cost;
      public Tabletop(double l, double w) : base(l, w) { }
      public double GetCost() {
         double cost;
         cost = GetArea() * 70;
         return cost;
      }
      public void Display() {
         base.Display();
         Console.WriteLine("Cost: {0}", GetCost());
      }
   }
   class ExecuteRectangle {
      static void Main(string[] args) {
         Tabletop t = new Tabletop(4.5, 7.5);
         t.Display();
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Length: 4.5
Width: 7.5
Area: 33.75
Cost: 2362.5

C#中的多重继承

C# does not support multiple inheritance 。 但是,您可以使用接口来实现多重继承。 以下程序演示了这一点 -

using System;
namespace InheritanceApplication {
   class Shape {
      public void setWidth(int w) {
         width = w;
      }
      public void setHeight(int h) {
         height = h;
      }
      protected int width;
      protected int height;
   }
   // Base class PaintCost
   public interface PaintCost {
      int getCost(int area);
   }
   // Derived class
   class Rectangle : Shape, PaintCost {
      public int getArea() {
         return (width * height);
      }
      public int getCost(int area) {
         return area * 70;
      }
   }
   class RectangleTester {
      static void Main(string[] args) {
         Rectangle Rect = new Rectangle();
         int area;
         Rect.setWidth(5);
         Rect.setHeight(7);
         area = Rect.getArea();
         // Print the area of the object.
         Console.WriteLine("Total area: {0}",  Rect.getArea());
         Console.WriteLine("Total paint cost: ${0}" , Rect.getCost(area));
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Total area: 35
Total paint cost: $2450

C# - Polymorphism

polymorphism这个词意味着有许多形式。 在面向对象的编程范例中,多态性通常表示为“一个接口,多个函数”。

多态性可以是静态的或动态的。 在static polymorphism ,对函数的响应在编译时确定。 在dynamic polymorphism ,它在运行时决定。

静态多态性

在编译期间将函数与对象链接的机制称为早期绑定。 它也称为静态绑定。 C#提供了两种实现静态多态的技术。 他们是 -

  • 函数重载
  • 运算符重载

我们将在下一章讨论运算符重载。

功能重载

您可以在同一范围内对同一函数名称具有多个定义。 函数的定义必须通过参数列表中的参数的类型和/或数量彼此不同。 您不能重载仅由返回类型不同的函数声明。

以下示例显示使用print()函数打印不同的数据类型 -

using System;
namespace PolymorphismApplication {
   class Printdata {
      void print(int i) {
         Console.WriteLine("Printing int: {0}", i );
      }
      void print(double f) {
         Console.WriteLine("Printing float: {0}" , f);
      }
      void print(string s) {
         Console.WriteLine("Printing string: {0}", s);
      }
      static void Main(string[] args) {
         Printdata p = new Printdata();
         // Call print to print integer
         p.print(5);
         // Call print to print float
         p.print(500.263);
         // Call print to print string
         p.print("Hello C++");
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Printing int: 5
Printing float: 500.263
Printing string: Hello C++

动态多态性

C#允许您创建用于提供接口的部分类实现的抽象类。 当派生类继承它时,实现完成。 Abstract类包含抽象方法,这些方法由派生类实现。 派生类具有更多专用功能。

以下是关于抽象类的规则 -

  • 您无法创建抽象类的实例

  • 您不能在抽象类之外声明抽象方法

  • 当一个类被声明为sealed ,它不能被继承,抽象类不能被声明为密封。

以下程序演示了一个抽象类 -

using System;
namespace PolymorphismApplication {
   abstract class Shape {
      public abstract int area();
   }
   class Rectangle:  Shape {
      private int length;
      private int width;
      public Rectangle( int a = 0, int b = 0) {
         length = a;
         width = b;
      }
      public override int area () { 
         Console.WriteLine("Rectangle class area :");
         return (width * length); 
      }
   }
   class RectangleTester {
      static void Main(string[] args) {
         Rectangle r = new Rectangle(10, 7);
         double a = r.area();
         Console.WriteLine("Area: {0}",a);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Rectangle class area :
Area: 70

如果要在要继承的类中实现的类中定义函数,则使用virtual函数。 虚函数可以在不同的继承类中以不同方式实现,并且将在运行时决定对这些函数的调用。

动态多态性由abstract classesvirtual functions

以下程序演示了这一点 -

using System;
namespace PolymorphismApplication {
   class Shape {
      protected int width, height;
      public Shape( int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      public virtual int area() {
         Console.WriteLine("Parent class area :");
         return 0;
      }
   }
   class Rectangle: Shape {
      public Rectangle( int a = 0, int b = 0): base(a, b) {
      }
      public override int area () {
         Console.WriteLine("Rectangle class area :");
         return (width * height); 
      }
   }
   class Triangle: Shape {
      public Triangle(int a = 0, int b = 0): base(a, b) {
      }
      public override int area() {
         Console.WriteLine("Triangle class area :");
         return (width * height/2); 
      }
   }
   class Caller {
      public void CallArea(Shape sh) {
         int a;
         a = sh.area();
         Console.WriteLine("Area: {0}", a);
      }
   }  
   class Tester {
      static void Main(string[] args) {
         Caller c = new Caller();
         Rectangle r = new Rectangle(10, 7);
         Triangle t = new Triangle(10, 5);
         c.CallArea(r);
         c.CallArea(t);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Rectangle class area:
Area: 70
Triangle class area:
Area: 25

C# - Operator Overloading

您可以重新定义或重载C#中可用的大多数内置运算符。 因此,程序员也可以使用具有用户定义类型的运算符。 重载运算符是具有特殊名称的函数,关键字operator后跟要定义的运算符的符号。 与任何其他函数类似,重载运算符具有返回类型和参数列表。

例如,通过以下功能 -

public static Box operator+ (Box b, Box c) {
   Box box = new Box();
   box.length = b.length + c.length;
   box.breadth = b.breadth + c.breadth;
   box.height = b.height + c.height;
   return box;
}

上面的函数为用户定义的类Box实现了加法运算符(+)。 它添加了两个Box对象的属性并返回结果Box对象。

实现运算符重载

以下程序显示了完整的实现 -

using System;
namespace OperatorOvlApplication {
   class Box {
      private double length;   // Length of a box
      private double breadth;  // Breadth of a box
      private double height;   // Height of a box
      public double getVolume() {
         return length * breadth * height;
      }
      public void setLength( double len ) {
         length = len;
      }
      public void setBreadth( double bre ) {
         breadth = bre;
      }
      public void setHeight( double hei ) {
         height = hei;
      }
      // Overload + operator to add two Box objects.
      public static Box operator+ (Box b, Box c) {
         Box box = new Box();
         box.length = b.length + c.length;
         box.breadth = b.breadth + c.breadth;
         box.height = b.height + c.height;
         return box;
      }
   }
   class Tester {
      static void Main(string[] args) {
         Box Box1 = new Box();   // Declare Box1 of type Box
         Box Box2 = new Box();   // Declare Box2 of type Box
         Box Box3 = new Box();   // Declare Box3 of type Box
         double volume = 0.0;    // Store the volume of a box here
         // box 1 specification
         Box1.setLength(6.0);
         Box1.setBreadth(7.0);
         Box1.setHeight(5.0);
         // box 2 specification
         Box2.setLength(12.0);
         Box2.setBreadth(13.0);
         Box2.setHeight(10.0);
         // volume of box 1
         volume = Box1.getVolume();
         Console.WriteLine("Volume of Box1 : {0}", volume);
         // volume of box 2
         volume = Box2.getVolume();
         Console.WriteLine("Volume of Box2 : {0}", volume);
         // Add two object as follows:
         Box3 = Box1 + Box2;
         // volume of box 3
         volume = Box3.getVolume();
         Console.WriteLine("Volume of Box3 : {0}", volume);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

可过载和不可重载的运算符

下表描述了C#中运算符的重载能力 -

Sr.No. 运算符和描述
1

+, -, !, ~, ++, --

这些一元运算符占用一个操作数,可以重载。

2

+, -, *, /, %

这些二元运算符占用一个操作数,可以重载。

3

==, !=, 《, 》, 《=, 》=

比较运算符可能会过载。

4

&&, ||

条件逻辑运算符不能直接重载。

5

+=, -=, *=, /=, %=

赋值运算符不能重载。

6

=, ., ?:, -》, new, is, sizeof, typeof

这些运算符不能超载。

例子 (Example)

根据上述讨论,让我们扩展前面的例子,并重载几个运算符 -

using System;
namespace OperatorOvlApplication {
   class Box {
      private double length;    // Length of a box
      private double breadth;   // Breadth of a box
      private double height;    // Height of a box
      public double getVolume() {
         return length * breadth * height;
      }
      public void setLength( double len ) {
         length = len;
      }
      public void setBreadth( double bre ) {
         breadth = bre;
      }
      public void setHeight( double hei ) {
         height = hei;
      }
      // Overload + operator to add two Box objects.
      public static Box operator+ (Box b, Box c) {
         Box box = new Box();
         box.length = b.length + c.length;
         box.breadth = b.breadth + c.breadth;
         box.height = b.height + c.height;
         return box;
      }
      public static bool operator == (Box lhs, Box rhs) {
         bool status = false;
         if (lhs.length == rhs.length && lhs.height == rhs.height && lhs.breadth == rhs.breadth) {
            status = true;
         }
         return status;
      }
      public static bool operator !=(Box lhs, Box rhs) {
         bool status = false;
         if (lhs.length != rhs.length || lhs.height != rhs.height || lhs.breadth != rhs.breadth) {
            status = true;
         }
         return status;
      }
      public static bool operator <(Box lhs, Box rhs) {
         bool status = false;
         if (lhs.length < rhs.length && lhs.height < rhs.height && lhs.breadth < rhs.breadth) {
            status = true;
         }
         return status;
      }
      public static bool operator >(Box lhs, Box rhs) {
         bool status = false;
         if (lhs.length > rhs.length && lhs.height > rhs.height && lhs.breadth > rhs.breadth) {
            status = true;
         }
         return status;
      }
      public static bool operator <=(Box lhs, Box rhs) {
         bool status = false;
         if (lhs.length <= rhs.length && lhs.height <= rhs.height && lhs.breadth <= rhs.breadth) {
            status = true;
         }
         return status;
      }
      public static bool operator >=(Box lhs, Box rhs) {
         bool status = false;
         if (lhs.length >= rhs.length && lhs.height >= rhs.height && lhs.breadth >= rhs.breadth) {
            status = true;
         }
         return status;
      }
      public override string ToString() {
         return String.Format("({0}, {1}, {2})", length, breadth, height);
      }
   }
   class Tester {
      static void Main(string[] args) {
         Box Box1 = new Box();   // Declare Box1 of type Box
         Box Box2 = new Box();   // Declare Box2 of type Box
         Box Box3 = new Box();   // Declare Box3 of type Box
         Box Box4 = new Box();
         double volume = 0.0;    // Store the volume of a box here
         // box 1 specification
         Box1.setLength(6.0);
         Box1.setBreadth(7.0);
         Box1.setHeight(5.0);
         // box 2 specification
         Box2.setLength(12.0);
         Box2.setBreadth(13.0);
         Box2.setHeight(10.0);
         //displaying the Boxes using the overloaded ToString():
         Console.WriteLine("Box 1: {0}", Box1.ToString());
         Console.WriteLine("Box 2: {0}", Box2.ToString());
         // volume of box 1
         volume = Box1.getVolume();
         Console.WriteLine("Volume of Box1 : {0}", volume);
         // volume of box 2
         volume = Box2.getVolume();
         Console.WriteLine("Volume of Box2 : {0}", volume);
         // Add two object as follows:
         Box3 = Box1 + Box2;
         Console.WriteLine("Box 3: {0}", Box3.ToString());
         // volume of box 3
         volume = Box3.getVolume();
         Console.WriteLine("Volume of Box3 : {0}", volume);
         //comparing the boxes
         if (Box1 > Box2)
            Console.WriteLine("Box1 is greater than Box2");
         else
            Console.WriteLine("Box1 is  greater than Box2");
         if (Box1 < Box2)
            Console.WriteLine("Box1 is less than Box2");
         else
            Console.WriteLine("Box1 is not less than Box2");
         if (Box1 >= Box2)
            Console.WriteLine("Box1 is greater or equal to Box2");
         else
            Console.WriteLine("Box1 is not greater or equal to Box2");
         if (Box1 <= Box2)
            Console.WriteLine("Box1 is less or equal to Box2");
         else
            Console.WriteLine("Box1 is not less or equal to Box2");
         if (Box1 != Box2)
            Console.WriteLine("Box1 is not equal to Box2");
         else
            Console.WriteLine("Box1 is not greater or equal to Box2");
         Box4 = Box3;
         if (Box3 == Box4)
            Console.WriteLine("Box3 is equal to Box4");
         else
            Console.WriteLine("Box3 is not equal to Box4");
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Box 1: (6, 7, 5)
Box 2: (12, 13, 10)
Volume of Box1 : 210
Volume of Box2 : 1560
Box 3: (18, 20, 15)
Volume of Box3 : 5400
Box1 is not greater than Box2
Box1 is less than Box2
Box1 is not greater or equal to Box2
Box1 is less or equal to Box2
Box1 is not equal to Box2
Box3 is equal to Box4

C# - Interfaces

接口被定义为一个语法合约,继承接口的所有类都应该遵循。 接口定义了语法契约的'what'部分,派生类定义了语法契约的'how'部分。

接口定义属性,方法和事件,它们是接口的成员。 接口仅包含成员的声明。 派生类负责定义成员。 它通常有助于提供派生类将遵循的标准结构。

抽象类在某种程度上用于相同的目的,但是,当基类只声明少数方法并且派生类实现功能时,它们主要被使用。

声明接口

接口使用interface关键字声明。 它类声明类。 接口语句默认是公共的。 以下是接口声明的示例 -

public interface ITransactions {
   // interface members
   void showTransaction();
   double getAmount();
}

例子 (Example)

以下示例演示了上述接口的实现 -

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
namespace InterfaceApplication {
   public interface ITransactions {
      // interface members
      void showTransaction();
      double getAmount();
   }
   public class Transaction : ITransactions {
      private string tCode;
      private string date;
      private double amount;
      public Transaction() {
         tCode = " ";
         date = " ";
         amount = 0.0;
      }
      public Transaction(string c, string d, double a) {
         tCode = c;
         date = d;
         amount = a;
      }
      public double getAmount() {
         return amount;
      }
      public void showTransaction() {
         Console.WriteLine("Transaction: {0}", tCode);
         Console.WriteLine("Date: {0}", date);
         Console.WriteLine("Amount: {0}", getAmount());
      }
   }
   class Tester {
      static void Main(string[] args) {
         Transaction t1 = new Transaction("001", "8/10/2012", 78900.00);
         Transaction t2 = new Transaction("002", "9/10/2012", 451900.00);
         t1.showTransaction();
         t2.showTransaction();
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Transaction: 001
Date: 8/10/2012
Amount: 78900
Transaction: 002
Date: 9/10/2012
Amount: 451900

C# - Namespaces

namespace旨在提供一种方法来保持一组名称与另一组名称分离。 在一个名称空间中声明的类名称与在另一个名称空间中声明的相同类名称不冲突。

定义命名空间

命名空间定义以关键字namespace空间开头,后跟命名空间名称,如下所示 -

namespace namespace_name {
   // code declarations
}

要调用函数或变量的启用命名空间的版本,请按如下方式添加命名空间名称 -

namespace_name.item_name;

以下程序演示了名称空间的使用 -

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 namespace指令避免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 {
   // code declarations
   namespace namespace_name2 {
      // code declarations
   }
}

您可以使用点(。)运算符访问嵌套命名空间的成员,如下所示 -

using System;
using first_space;
using first_space.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

C# - Preprocessor Directives

预处理程序指令指示编译器在实际编译开始之前预处理信息。

所有预处理程序指令都以#开头,并且只有空格字符可能出现在一行上的预处理程序指令之前。 预处理程序指令不是语句,因此它们不以分号(;)结尾。

C#编译器没有单独的预处理器; 但是,指令的处理就像有一个指令一样。 在C#中,预处理程序指令用于帮助进行条件编译。 与C和C ++指令不同,它们不用于创建宏。 预处理程序指令必须是一行上的唯一指令。

C#中的预处理器指令

下表列出了C#中可用的预处理程序指令 -

Sr.No. 预处理器指令和描述
1

#define

它定义了一系列字符,称为符号。

2

#undef

它允许您取消定义符号。

3

#if

它允许测试符号或符号以查看它们是否评估为真。

4

#else

它允许创建复合条件指令以及#if。

5

#elif

它允许创建复合条件指令。

6

#endif

指定条件指令的结束。

7

#line

它允许您修改编译器的行号和(可选)文件名输出以查找错误和警告。

8

#error

它允许从代码中的特定位置生成错误。

9

#warning

它允许从代码中的特定位置生成一级警告。

10

#region

它允许您指定在使用Visual Studio代码编辑器的大纲功能时可以展开或折叠的代码块。

11

#endregion

它标志着#region块的结束。

#define预处理器 (The #define Preprocessor)

#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指令创建条件指令。 条件指令对于测试一个或多个符号以检查它们是否计算为true非常有用。 如果它们的计算结果为true,则编译器会评估#if和next指令之间的所有代码。

条件指令的语法是 -

#if symbol [operator symbol]...

其中, symbol是要测试的符号的名称。 您也可以使用true和false,或者使用negation运算符添加符号。

operator symbol是用于评估符号的运算符。 运算符可以是以下任何一种 -

  • == (equality)
  • != (inequality)
  • && (and)
  • || (要么)

您还可以使用括号对符号和运算符进行分组。 条件指令用于编译调试版本的代码或编译特定配置时的代码。 以#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# - Regular Expressions

regular expression是可以与输入文本匹配的模式。 .Net框架提供了允许这种匹配的正则表达式引擎。 模式由一个或多个字符文字,运算符或构造组成。

用于定义正则表达式的构造

有各种类别的字符,运算符和构造,可用于定义正则表达式。 单击以下链接以查找这些构造。

正则表达式

Regex类用于表示正则表达式。 它有以下常用方法 -

Sr.No. 方法和描述
1

public bool IsMatch(string input)

指示Regex构造函数中指定的正则表达式是否在指定的输入字符串中找到匹配项。

2

public bool IsMatch(string input, int startat)

指示在Regex构造函数中指定的正则表达式是否在指定的输入字符串中找到匹配项,从字符串中指定的起始位置开始。

3

public static bool IsMatch(string input, string pattern)

指示指定的正则表达式是否在指定的输入字符串中找到匹配项。

4

public MatchCollection Matches(string input)

在指定的输入字符串中搜索所有正则表达式。

5

public string Replace(string input, string replacement)

在指定的输入字符串中,将所有与正则表达式模式匹配的字符串替换为指定的替换字符串。

6

public string[] Split(string input)

将输入字符串拆分为由正则表达式构造函数中指定的正则表达式模式定义的位置处的子字符串数组。

有关方法和属性的完整列表,请阅读有关C#的Microsoft文档。

例子1 (Example 1)

以下示例匹配以'S'开头的单词 -

using System;
using System.Text.RegularExpressions;
namespace RegExApplication {
   class Program {
      private static void showMatch(string text, string expr) {
         Console.WriteLine("The Expression: " + expr);
         MatchCollection mc = Regex.Matches(text, expr);
         foreach (Match m in mc) {
            Console.WriteLine(m);
         }
      }
      static void Main(string[] args) {
         string str = "A Thousand Splendid Suns";
         Console.WriteLine("Matching words that start with 'S': ");
         showMatch(str, @"\bS\S*");
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Matching words that start with 'S':
The Expression: \bS\S*
Splendid
Suns

例子2 (Example 2)

以下示例匹配以“m”开头并以“e”结尾的单词 -

using System;
using System.Text.RegularExpressions;
namespace RegExApplication {
   class Program {
      private static void showMatch(string text, string expr) {
         Console.WriteLine("The Expression: " + expr);
         MatchCollection mc = Regex.Matches(text, expr);
         foreach (Match m in mc) {
            Console.WriteLine(m);
         }
      }
      static void Main(string[] args) {
         string str = "make maze and manage to measure it";
         Console.WriteLine("Matching words start with 'm' and ends with 'e':");
         showMatch(str, @"\bm\S*e\b");
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Matching words start with 'm' and ends with 'e':
The Expression: \bm\S*e\b
make
maze
manage
measure

例子3 (Example 3)

此示例替换了额外的空白区域 -

using System;
using System.Text.RegularExpressions;
namespace RegExApplication {
   class Program {
      static void Main(string[] args) {
         string input = "Hello   World   ";
         string pattern = "\\s+";
         string replacement = " ";
         Regex rgx = new Regex(pattern);
         string result = rgx.Replace(input, replacement);
         Console.WriteLine("Original String: {0}", input);
         Console.WriteLine("Replacement String: {0}", result);    
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Original String: Hello World   
Replacement String: Hello World   

C# - Exception Handling

例外是在执行程序期间出现的问题。 AC#exception是对程序运行时出现的异常情况的响应,例如尝试除以零。

例外提供了一种将控制从程序的一个部分转移到另一个部分的方法。 C#异常处理基于四个关键字: trycatchfinallythrow

  • try - try块标识激活特定异常的代码块。 接下来是一个或多个捕获块。

  • catch - 程序在程序中要处理问题的位置捕获异常并使用异常处理程序。 catch关键字表示捕获异常。

  • finally - finally块用于执行一组给定的语句,无论是抛出还是不抛出异常。 例如,如果打开文件,则必须关闭它是否引发异常。

  • throw - 当问题出现时,程序会抛出异常。 这是使用throw关键字完成的。

语法 (Syntax)

假设块引发异常,则方法使用try和catch关键字的组合捕获异常。 try/catch块放在可能生成异常的代码周围。 try/catch块中的代码称为受保护代码,使用try/catch的语法如下所示 -

try {
   // statements causing exception
} catch( ExceptionName e1 ) {
   // error handling code
} catch( ExceptionName e2 ) {
   // error handling code
} catch( ExceptionName eN ) {
   // error handling code
} finally {
   // statements to be executed
}

如果try块在不同情况下引发多个异常,您可以列出多个catch语句以捕获不同类型的异常。

C#中的异常类

C#异常由类表示。 C#中的异常类主要直接或间接地从System.Exception类派生。 从System.Exception类派生的一些异常类是System.ApplicationExceptionSystem.SystemException类。

System.ApplicationException类支持应用程序生成的异常。 因此,程序员定义的异常应该来自这个类。

System.SystemException类是所有预定义系统异常的基类。

下表提供了从Sytem.SystemException类派生的一些预定义异常类 -

Sr.No. 异常类和描述
1

System.IO.IOException

处理I/O错误。

2

System.IndexOutOfRangeException

处理方法引用数组索引超出范围时生成的错误。

3

System.ArrayTypeMismatchException

处理类型与数组类型不匹配时生成的错误。

4

System.NullReferenceException

处理引用空对象时生成的错误。

5

System.DivideByZeroException

处理将被除数除以零所产生的错误。

6

System.InvalidCastException

处理在类型转换期间生成的错误。

7

System.OutOfMemoryException

处理由于空闲内存不足而产生的错误。

8

System.StackOverflowException

处理堆栈溢出产生的错误。

处理例外情况

C#以try和catch块的形式提供了异常处理的结构化解决方案。 使用这些块,核心程序语句与错误处理语句分开。

这些错误处理块是使用trycatchfinally关键字实现的。 以下是在零条件发生时抛出异常的示例 -

using System;
namespace ErrorHandlingApplication {
   class DivNumbers {
      int result;
      DivNumbers() {
         result = 0;
      }
      public void division(int num1, int num2) {
         try {
            result = num1/num2;
         } catch (DivideByZeroException e) {
            Console.WriteLine("Exception caught: {0}", e);
         } finally {
            Console.WriteLine("Result: {0}", result);
         }
      }
      static void Main(string[] args) {
         DivNumbers d = new DivNumbers();
         d.division(25, 0);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Exception caught: System.DivideByZeroException: Attempted to divide by zero. 
at ...
Result: 0

创建用户定义的异常

您还可以定义自己的例外。 用户定义的异常类派生自Exception类。 以下示例演示了这一点 -

using System;
namespace UserDefinedException {
   class TestTemperature {
      static void Main(string[] args) {
         Temperature temp = new Temperature();
         try {
            temp.showTemp();
         } catch(TempIsZeroException e) {
            Console.WriteLine("TempIsZeroException: {0}", e.Message);
         }
         Console.ReadKey();
      }
   }
}
public class TempIsZeroException: Exception {
   public TempIsZeroException(string message): base(message) {
   }
}
public class Temperature {
   int temperature = 0;
   public void showTemp() {
      if(temperature == 0) {
         throw (new TempIsZeroException("Zero Temperature found"));
      } else {
         Console.WriteLine("Temperature: {0}", temperature);
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

TempIsZeroException: Zero Temperature found

投掷物体

如果对象直接或间接派生自System.Exception类,则可以抛出该对象。 您可以在catch块中使用throw语句将当前对象抛出为 -

Catch(Exception e) {
   ...
   Throw e
}

C# - File I/O

file是存储在具有特定名称和目录路径的磁盘中的数据集合。 打开文件进行读取或写入时,它将变为stream

流基本上是通过通信路径的字节序列。 有两个主要流: input streamoutput streaminput stream用于从文件读取数据(读取操作), output stream用于写入文件(写入操作)。

C#I/O类

System.IO命名空间有各种类,用于对文件执行大量操作,例如创建和删除文件,读取或写入文件,关闭文件等。

下表显示了System.IO命名空间中一些常用的非抽象类 -

Sr.No. I/O类和描述
1

BinaryReader

从二进制流中读取原始数据。

2

BinaryWriter

以二进制格式写入原始数据。

3

BufferedStream

用于字节流的临时存储。

4

Directory

帮助操纵目录结构。

5

DirectoryInfo

用于对目录执行操作。

6

DriveInfo

提供驱动器的信息。

7

File

帮助操纵文件。

8

FileInfo

用于对文件执行操作。

9

FileStream

用于读取和写入文件中的任何位置。

10

MemoryStream

用于随机访问存储在内存中的流数据。

11

Path

对路径信息执行操作。

12

StreamReader

用于从字节流中读取字符。

13

StreamWriter

用于将字符写入流。

14

StringReader

用于从字符串缓冲区读取。

15

StringWriter

用于写入字符串缓冲区。

FileStream类

System.IO命名空间中的FileStream类有助于读取,写入和关闭文件。 该类派生自抽象类Stream。

您需要创建FileStream对象以创建新文件或打开现有文件。 创建FileStream对象的语法如下 -

FileStream <object_name> = new FileStream( <file_name>, <FileMode Enumerator>,
   <FileAccess Enumerator>, <FileShare Enumerator>);

例如,我们创建一个FileStream对象F来读取名为sample.txt as shown的文件sample.txt as shown -

FileStream F = new FileStream("sample.txt", FileMode.Open, FileAccess.Read,
   FileShare.Read);
Sr.No. 参数和描述
1

FileMode

FileMode枚举器定义了打开文件的各种方法。 FileMode枚举器的成员是 -

  • Append - 它打开现有文件并将光标放在文件末尾,或者如果文件不存在则创建文件。

  • Create - 它创建一个新文件。

  • CreateNew - 它指定操作系统应该创建一个新文件。

  • Open - 它打开一个现有文件。

  • OpenOrCreate - 它指定操作系统应该打开文件(如果存在),否则应该创建一个新文件。

  • Truncate - 它打开一个现有文件并将其大小截断为零字节。

2

FileAccess

FileAccess枚举器具有成员: ReadReadWriteWrite

3

FileShare

FileShare枚举器具有以下成员 -

  • Inheritable - 它允许文件句柄将继承传递给子进程

  • None - 它拒绝当前文件的共享

  • Read - 它允许打开文件进行Read

  • ReadWrite - 它允许打开文件进行读写

  • Write - 它允许打开文件进行写入

例子 (Example)

以下程序演示了使用FileStream类 -

using System;
using System.IO;
namespace FileIOApplication {
   class Program {
      static void Main(string[] args) {
         FileStream F = new FileStream("test.dat", FileMode.OpenOrCreate, 
            FileAccess.ReadWrite);
         for (int i = 1; i <= 20; i++) {
            F.WriteByte((byte)i);
         }
         F.Position = 0;
         for (int i = 0; i <= 20; i++) {
            Console.Write(F.ReadByte() + " ");
         }
         F.Close();
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -1

C#中的高级文件操作

前面的示例在C#中提供了简单的文件操作。 但是,要利用C#System.IO类的强大功能,您需要了解这些类的常用属性和方法。

Sr.No. 主题和描述
1 读取和写入文本文件

它涉及读取和写入文本文件。 StreamReaderStreamWriter类有助于完成它。

2 读取和写入二进制文件

它涉及读取和写入二进制文件。 BinaryReaderBinaryWriter类有助于实现此目的。

3 操纵Windows文件系统

它为C#程序员提供了浏览和定位Windows文件和目录的能力。

C# - Attributes

attribute是一个声明性标记,用于向运行时传递有关程序中各种元素(如类,方法,结构,枚举器,程序集等)的行为的信息。 您可以使用属性向程序添加声明性信息。 声明性标记由位于其所用元素上方的方括号([])括号表示。

属性用于向程序添加元数据,例如编译器指令和其他信息,例如注释,描述,方法和类。 .Net Framework提供两种类型的属性: the pre-defined属性和custom built属性。

指定属性

指定属性的语法如下 -

[attribute(positional_parameters, name_parameter = value, ...)]
element

属性的名称及其值在方括号内指定,在应用该属性的元素之前。 位置参数指定基本信息,名称参数指定可选信息。

预定义属性

.Net Framework提供三个预定义的属性 -

  • AttributeUsage
  • Conditional
  • Obsolete

AttributeUsage (AttributeUsage)

预定义属性AttributeUsage描述了如何使用自定义属性类。 它指定可以应用属性的项目类型。

指定此属性的语法如下 -

[AttributeUsage (
   validon,
   AllowMultiple = allowmultiple,
   Inherited = inherited
)]

Where,

  • 参数validon指定可以放置属性的语言元素。 它是枚举器AttributeTargets的值的组合。 默认值为AttributeTargets.All

  • 参数allowmultiple (可选)为此属性的AllowMultiple属性提供值,即布尔值。 如果是,则属性为多用途。 默认值为false(单次使用)。

  • 继承的参数(可选)为此属性的Inherited属性提供值,即布尔值。 如果为true,则属性由派生类继承。 默认值为false(未继承)。

例如,

[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property, 
AllowMultiple = true)]

有条件的(Conditional)

此预定义属性标记条件方法,其执行取决于指定的预处理标识符。

它会导致方法调用的条件编译,具体取决于指定的值,如DebugTrace 。 例如,它在调试代码时显示变量的值。

指定此属性的语法如下 -

[Conditional(
   conditionalSymbol
)]

例如,

[Conditional("DEBUG")]

以下示例演示了该属性 -

#define DEBUG
using System;
using System.Diagnostics;
public class Myclass {
   [Conditional("DEBUG")]
   public static void Message(string msg) {
      Console.WriteLine(msg);
   }
}
class Test {
   static void function1() {
      Myclass.Message("In Function 1.");
      function2();
   }
   static void function2() {
      Myclass.Message("In Function 2.");
   }
   public static void Main() {
      Myclass.Message("In Main function.");
      function1();
      Console.ReadKey();
   }
}

编译并执行上述代码时,会产生以下结果 -

In Main function
In Function 1
In Function 2

过时 (Obsolete)

此预定义属性标记不应使用的程序实体。 它使您能够通知编译器丢弃特定的目标元素。 例如,当在类中使用新方法时,如果您仍希望在类中保留旧方法,则可以通过显示应使用新方法的消息而不是旧方法将其标记为过时。

指定此属性的语法如下 -

[Obsolete (
   message
)]
[Obsolete (
   message,
   iserror
)]

Where,

  • 参数message是一个字符串,用于描述项目过时的原因以及使用的内容。

  • 参数iserror是一个布尔值。 如果其值为true,则编译器应将该项的使用视为错误。 默认值为false(编译器生成警告)。

以下程序演示了这一点 -

using System;
public class MyClass {
   [Obsolete("Don't use OldMethod, use NewMethod instead", true)]
   static void OldMethod() {
      Console.WriteLine("It is the old method");
   }
   static void NewMethod() {
      Console.WriteLine("It is the new method"); 
   }
   public static void Main() {
      OldMethod();
   }
}

当您尝试编译该程序时,编译器会显示一条错误消息,指出 -

 Don't use OldMethod, use NewMethod instead

创建自定义属性

.Net Framework允许创建可用于存储声明性信息的自定义属性,并且可以在运行时检索。 根据设计标准和应用需求,此信息可与任何目标元素相关。

创建和使用自定义属性涉及四个步骤 -

  • 声明自定义属性
  • 构造自定义属性
  • 在目标程序元素上应用自定义属性
  • 通过反射访问属性

最后一步涉及编写一个简单的程序来读取元数据以查找各种符号。 元数据是关于用于描述其他数据的数据或信息的数据。 该程序应使用反射来在运行时访问属性。 我们将在下一章讨论。

声明自定义属性

应从System.Attribute类派生新的自定义属性。 例如,

//a custom attribute BugFix to be assigned to a class and its members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute

在前面的代码中,我们声明了一个名为DeBugInfo的自定义属性。

构造自定义属性

让我们构造一个名为DeBugInfo的自定义属性,它存储通过调试任何程序获得的信息。 让它存储以下信息 -

  • 错误的代号
  • 识别错误的开发人员的姓名
  • 上次审查代码的日期
  • 用于存储开发人员备注的字符串消息

DeBugInfo类有三个用于存储前三个信息的私有属性和一个用于存储消息的公共属性。 因此,错误号,开发人员的姓名和审查日期是DeBugInfo类的位置参数,消息是可选的或命名参数。

每个属性必须至少有一个构造函数。 位置参数应该通过构造函数传递。 以下代码显示了DeBugInfo类 -

//a custom attribute BugFix to be assigned to a class and its members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute {
   private int bugNo;
   private string developer;
   private string lastReview;
   public string message;
   public DeBugInfo(int bg, string dev, string d) {
      this.bugNo = bg;
      this.developer = dev;
      this.lastReview = d;
   }
   public int BugNo {
      get {
         return bugNo;
      }
   }
   public string Developer {
      get {
         return developer;
      }
   }
   public string LastReview {
      get {
         return lastReview;
      }
   }
   public string Message {
      get {
         return message;
      }
      set {
         message = value;
      }
   }
}

应用自定义属性

通过将其放置在其目标之前来应用该属性 -

[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle {
   //member variables
   protected double length;
   protected double width;
   public Rectangle(double l, double w) {
      length = l;
      width = w;
   }
   [DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")]
   public double GetArea() {
      return length * width;
   }
   [DeBugInfo(56, "Zara Ali", "19/10/2012")]
   public void Display() {
      Console.WriteLine("Length: {0}", length);
      Console.WriteLine("Width: {0}", width);
      Console.WriteLine("Area: {0}", GetArea());
   }
}

在下一章中,我们使用Reflection类对象检索属性信息。

C# - Reflection

Reflection对象用于在运行时获取类型信息。 提供对正在运行的程序的元数据的访问的类位于System.Reflection命名空间中。

System.Reflection命名空间包含的类允许您获取有关应用程序的信息,并动态地向应用程序添加类型,值和对象。

反射的应用

反射有以下应用 -

  • 它允许在运行时查看属性信息。

  • 它允许检查程序集中的各种类型并实例化这些类型。

  • 它允许后期绑定到方法和属性

  • 它允许在运行时创建新类型,然后使用这些类型执行某些任务。

查看元数据

我们在前一章中已经提到使用反射可以查看属性信息。

需要初始化System.Reflection类的MemberInfo对象以发现与类关联的属性。 为此,您可以定义目标类的对象,如下所示:

System.Reflection.MemberInfo info = typeof(MyClass);

以下程序演示了这一点 -

using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute {
   public readonly string Url;
   public string Topic   // Topic is a named parameter {
      get {
         return topic;
      }
      set {
         topic = value;
      }
   }
   public HelpAttribute(string url)   // url is a positional parameter {
      this.Url = url;
   }
   private string topic;
}
[HelpAttribute("Information on the class MyClass")]
class MyClass {
}
namespace AttributeAppl {
   class Program {
      static void Main(string[] args) {
         System.Reflection.MemberInfo info = typeof(MyClass);
         object[] attributes = info.GetCustomAttributes(true);
         for (int i = 0; i < attributes.Length; i++) {
            System.Console.WriteLine(attributes[i]);
         }
         Console.ReadKey();
      }
   }
}

编译并运行时,它会显示附加到MyClass类的自定义属性的名称 -

HelpAttribute

例子 (Example)

在此示例中,我们使用DeBugInfo创建的DeBugInfo属性,并使用反射来读取Rectangle类中的元数据。

using System;
using System.Reflection;
namespace BugFixApplication {
   //a custom attribute BugFix to be
   //assigned to a class and its members
   [AttributeUsage(AttributeTargets.Class |
   AttributeTargets.Constructor |
   AttributeTargets.Field |
   AttributeTargets.Method |
   AttributeTargets.Property,
   AllowMultiple = true)]
   public class DeBugInfo : System.Attribute {
      private int bugNo;
      private string developer;
      private string lastReview;
      public string message;
      public DeBugInfo(int bg, string dev, string d) {
         this.bugNo = bg;
         this.developer = dev;
         this.lastReview = d;
      }
      public int BugNo {
         get {
            return bugNo;
         }
      }
      public string Developer {
         get {
            return developer;
         }
      }
      public string LastReview {
         get {
            return lastReview;
         }
      }
      public string Message {
         get {
            return message;
         }
         set {
            message = value;
         }
      }
   }
   [DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
   [DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
   class Rectangle {
      //member variables
      protected double length;
      protected double width;
      public Rectangle(double l, double w) {
         length = l;
         width = w;
      }
      [DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")]
      public double GetArea() {
         return length * width;
      }
      [DeBugInfo(56, "Zara Ali", "19/10/2012")]
      public void Display() {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }//end class Rectangle
   class ExecuteRectangle {
      static void Main(string[] args) {
         Rectangle r = new Rectangle(4.5, 7.5);
         r.Display();
         Type type = typeof(Rectangle);
         //iterating through the attribtues of the Rectangle class
         foreach (Object attributes in type.GetCustomAttributes(false)) {
            DeBugInfo dbi = (DeBugInfo)attributes;
            if (null != dbi) {
               Console.WriteLine("Bug no: {0}", dbi.BugNo);
               Console.WriteLine("Developer: {0}", dbi.Developer);
               Console.WriteLine("Last Reviewed: {0}", dbi.LastReview);
               Console.WriteLine("Remarks: {0}", dbi.Message);
            }
         }
         //iterating through the method attribtues
         foreach (MethodInfo m in type.GetMethods()) {
            foreach (Attribute a in m.GetCustomAttributes(true)) {
               DeBugInfo dbi = (DeBugInfo)a;
               if (null != dbi) {
                  Console.WriteLine("Bug no: {0}, for Method: {1}", dbi.BugNo, m.Name);
                  Console.WriteLine("Developer: {0}", dbi.Developer);
                  Console.WriteLine("Last Reviewed: {0}", dbi.LastReview);
                  Console.WriteLine("Remarks: {0}", dbi.Message);
               }
            }
         }
         Console.ReadLine();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Length: 4.5
Width: 7.5
Area: 33.75
Bug No: 49
Developer: Nuha Ali
Last Reviewed: 10/10/2012
Remarks: Unused variable
Bug No: 45
Developer: Zara Ali
Last Reviewed: 12/8/2012
Remarks: Return type mismatch
Bug No: 55, for Method: GetArea
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: Return type mismatch
Bug No: 56, for Method: Display
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: 

C# - Properties

Properties是类,结构和接口的命名成员。 类或结构中的成员变量或方法称为Fields 。 属性是字段的扩展,可以使用相同的语法进行访问。 它们使用accessors通过accessors器可以读取,写入或操纵私有字段的值。

属性未命名存储位置。 相反,它们具有读取,写入或计算其值的访问器。

例如,让我们有一个名为Student的类,其中包含年龄,名称和代码的私有字段。 我们不能直接从类范围外访问这些字段,但我们可以拥有访问这些私有字段的属性。

访问器 Accessors

属性的accessor包含有助于获取(读取或计算)或设置(写入)属性的可执行语句。 访问器声明可以包含get访问器,set访问器或两者。 例如 -

// Declare a Code property of type string:
public string Code {
   get {
      return code;
   }
   set {
      code = value;
   }
}
// Declare a Name property of type string:
public string Name {
   get {
      return name;
   }
   set {
      name = value;
   }
}
// Declare a Age property of type int:
public int Age { 
   get {
      return age;
   }
   set {
      age = value;
   }
}

例子 (Example)

以下示例演示了属性的使用 -

using System;
namespace iowiki {
   class Student {
      private string code = "N.A";
      private string name = "not known";
      private int age = 0;
      // Declare a Code property of type string:
      public string Code {
         get {
            return code;
         }
         set {
            code = value;
         }
      }
      // Declare a Name property of type string:
      public string Name {
         get {
            return name;
         }
         set {
            name = value;
         }
      }
      // Declare a Age property of type int:
      public int Age {
         get {
            return age;
         }
         set {
            age = value;
         }
      }
      public override string ToString() {
         return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
      }
   }
   class ExampleDemo {
      public static void Main() {
         // Create a new Student object:
         Student s = new Student();
         // Setting code, name and the age of the student
         s.Code = "001";
         s.Name = "Zara";
         s.Age = 9;
         Console.WriteLine("Student Info: {0}", s);
         //let us increase age
         s.Age += 1;
         Console.WriteLine("Student Info: {0}", s);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10

抽象属性

抽象类可以具有抽象属性,该属性应该在派生类中实现。 以下程序说明了这一点 -

using System;
namespace iowiki {
   public abstract class Person {
      public abstract string Name {
         get;
         set;
      }
      public abstract int Age {
         get;
         set;
      }
   }
   class Student : Person {
      private string code = "N.A";
      private string name = "N.A";
      private int age = 0;
      // Declare a Code property of type string:
      public string Code {
         get {
            return code;
         }
         set {
            code = value;
         }
      }
      // Declare a Name property of type string:
      public override string Name {
         get {
            return name;
         }
         set {
            name = value;
         }
      }
      // Declare a Age property of type int:
      public override int Age {
         get {
            return age;
         }
         set {
            age = value;
         }
      }
      public override string ToString() {
         return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
      }
   }
   class ExampleDemo {
      public static void Main() {
         // Create a new Student object:
         Student s = new Student();
         // Setting code, name and the age of the student
         s.Code = "001";
         s.Name = "Zara";
         s.Age = 9;
         Console.WriteLine("Student Info:- {0}", s);
         //let us increase age
         s.Age += 1;
         Console.WriteLine("Student Info:- {0}", s);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10

C# - Indexers

indexer允许对象进行索引,例如数组。 为类定义索引器时,此类的行为类似于virtual array 。 然后,您可以使用数组访问运算符([])访问此类的实例。

语法 (Syntax)

一维索引器具有以下语法 -

element-type this[int index] {
   // The get accessor.
   get {
      // return the value specified by index
   }
   // The set accessor.
   set {
      // set the value specified by index
   }
}

使用索引器

索引器的行为声明在某种程度上类似于属性。 与属性类似,您使用getset访问器来定义索引器。 但是,属性返回或设置特定数据成员,而索引器从对象实例返回或设置特定值。 换句话说,它将实例数据分解为更小的部分并索引每个部分,获取或设置每个部分。

定义属性涉及提供属性名称。 索引器没有使用名称定义,而是使用this关键字定义, this关键字引用对象实例。 以下示例演示了该概念 -

using System;
namespace IndexerApplication {
   class IndexedNames {
      private string[] namelist = new string[size];
      static public int size = 10;
      public IndexedNames() {
         for (int i = 0; i < size; i++)
         namelist[i] = "N. A.";
      }
      public string this[int index] {
         get {
            string tmp;
            if( index >= 0 && index <= size-1 ) {
               tmp = namelist[index];
            } else {
               tmp = "";
            }
            return ( tmp );
         }
         set {
            if( index >= 0 && index <= size-1 ) {
               namelist[index] = value;
            }
         }
      }
      static void Main(string[] args) {
         IndexedNames names = new IndexedNames();
         names[0] = "Zara";
         names[1] = "Riz";
         names[2] = "Nuha";
         names[3] = "Asif";
         names[4] = "Davinder";
         names[5] = "Sunil";
         names[6] = "Rubic";
         for ( int i = 0; i < IndexedNames.size; i++ ) {
            Console.WriteLine(names[i]);
         }
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.

重载的索引器

索引器可能会超载。 索引器也可以使用多个参数声明,每个参数可以是不同的类型。 索引不必是整数。 C#允许索引为其他类型,例如字符串。

以下示例演示了重载的索引器 -

using System;
namespace IndexerApplication {
   class IndexedNames {
      private string[] namelist = new string[size];
      static public int size = 10;
      public IndexedNames() {
         for (int i = 0; i < size; i++) {
            namelist[i] = "N. A.";
         }
      }
      public string this[int index] {
         get {
            string tmp;
            if( index >= 0 && index <= size-1 ) {
               tmp = namelist[index];
            } else {
               tmp = "";
            }
            return ( tmp );
         }
         set {
            if( index >= 0 && index <= size-1 ) {
               namelist[index] = value;
            }
         }
      }
      public int this[string name] {
         get {
            int index = 0;
            while(index < size) {
               if (namelist[index] == name) {
                return index;
               }
               index++;
            }
            return index;
         }
      }
      static void Main(string[] args) {
         IndexedNames names = new IndexedNames();
         names[0] = "Zara";
         names[1] = "Riz";
         names[2] = "Nuha";
         names[3] = "Asif";
         names[4] = "Davinder";
         names[5] = "Sunil";
         names[6] = "Rubic";
         //using the first indexer with int parameter
         for (int i = 0; i < IndexedNames.size; i++) {
            Console.WriteLine(names[i]);
         }
         //using the second indexer with the string parameter
         Console.WriteLine(names["Nuha"]);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.
2

C# - Delegates

C#委托类似于C或C ++中的函数指针。 delegate是一个引用类型变量,用于保存对方法的引用。 可以在运行时更改引用。

代表特别用于实现事件和回调方法。 所有委托都是从System.Delegate类隐式派生的。

宣布代表

委托声明确定委托可以引用的方法。 委托可以引用一种方法,该方法具有与委托相同的签名。

例如,考虑一个代表 -

public delegate int MyDelegate (string s);

前面的委托可用于引用具有单个string参数的任何方法,并返回int类型变量。

委托声明的语法是 -

delegate <return type> <delegate-name> <parameter list>

实例化代理

声明委托类型后,必须使用new关键字创建委托对象,并将其与特定方法关联。 创建委托时,传递给new表达式的参数类似于方法调用,但没有方法的参数。 例如 -

public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);

下面的示例演示了委托的声明,实例化和使用,该委托可用于引用采用整数参数并返回整数值的方法。

using System;
delegate int NumberChanger(int n);
namespace DelegateAppl {
   class TestDelegate {
      static int num = 10;
      public static int AddNum(int p) {
         num += p;
         return num;
      }
      public static int MultNum(int q) {
         num *= q;
         return num;
      }
      public static int getNum() {
         return num;
      }
      static void Main(string[] args) {
         //create delegate instances
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         //calling the methods using the delegate objects
         nc1(25);
         Console.WriteLine("Value of Num: {0}", getNum());
         nc2(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Value of Num: 35
Value of Num: 175

代表的多播

可以使用“+”运算符组合委托对象。 组合委托调用它组成的两个委托。 只能组成相同类型的代理。 “ - ”运算符可用于从组合委托中删除组件委托。

使用委托的此属性,您可以创建在调用委托时将调用的方法的调用列表。 这称为代表的multicasting 。 以下程序演示了代表的多播 -

using System;
delegate int NumberChanger(int n);
namespace DelegateAppl {
   class TestDelegate {
      static int num = 10;
      public static int AddNum(int p) {
         num += p;
         return num;
      }
      public static int MultNum(int q) {
         num *= q;
         return num;
      }
      public static int getNum() {
         return num;
      }
      static void Main(string[] args) {
         //create delegate instances
         NumberChanger nc;
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         nc = nc1;
         nc += nc2;
         //calling multicast
         nc(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Value of Num: 75

使用代表

以下示例演示了委托的用法。 委托printString可用于引用将字符串作为输入并且不返回任何内容的方法。

我们使用这个委托调用两个方法,第一个将字符串打印到控制台,第二个将它打印到文件 -

using System;
using System.IO;
namespace DelegateAppl {
   class PrintString {
      static FileStream fs;
      static StreamWriter sw;
      // delegate declaration
      public delegate void printString(string s);
      // this method prints to the console
      public static void WriteToScreen(string str) {
         Console.WriteLine("The String is: {0}", str);
      }
      //this method prints to a file
      public static void WriteToFile(string s) {
         fs = new FileStream("c:\\message.txt",
         FileMode.Append, FileAccess.Write);
         sw = new StreamWriter(fs);
         sw.WriteLine(s);
         sw.Flush();
         sw.Close();
         fs.Close();
      }
      // this method takes the delegate as parameter and uses it to
      // call the methods as required
      public static void sendString(printString ps) {
         ps("Hello World");
      }
      static void Main(string[] args) {
         printString ps1 = new printString(WriteToScreen);
         printString ps2 = new printString(WriteToFile);
         sendString(ps1);
         sendString(ps2);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

The String is: Hello World

C# - Events

Events是用户操作,例如按键,点击,鼠标移动等,或某些事件,例如系统生成的通知。 应用程序需要在事件发生时对其进行响应。 例如,中断。 事件用于进程间通信。

使用代理与事件

事件在类中声明和引发,并使用同一类或其他类中的委托与事件处理程序相关联。 包含事件的类用于发布事件。 这称为publisher类。 接受此事件的其他一些类称为subscriber类。 事件使用publisher-subscriber模型。

publisher是包含事件和委托定义的对象。 事件委托关联也在此对象中定义。 发布者类对象调用该事件,并将其通知给其他对象。

subscriber是接受事件并提供事件处理程序的对象。 发布者类中的委托调用订阅者类的方法(事件处理程序)。

宣布活动

要在类中声明事件,首先必须声明事件的委托类型。 例如,

public delegate string MyDel(string str);

接下来,使用event关键字声明事件本身 -

event MyDel MyEvent;

上面的代码定义了一个名为BoilerLogHandler的委托和一个名为BoilerLogHandler的事件,该事件在引发时调用委托。

例子 (Example)

using System;
namespace SampleApp {
   public delegate string MyDel(string str);
   class EventProgram {
      event MyDel MyEvent;
      public EventProgram() {
         this.MyEvent += new MyDel(this.WelcomeUser);
      }
      public string WelcomeUser(string username) {
         return "Welcome " + username;
      }
      static void Main(string[] args) {
         EventProgram obj1 = new EventProgram();
         string result = obj1.MyEvent("IOWIKI");
         Console.WriteLine(result);
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Welcome IOWIKI

C# - Collections

集合类是用于数据存储和检索的专用类。 这些类为堆栈,队列,列表和哈希表提供支持。 大多数集合类实现相同的接口。

集合类用于各种目的,例如动态地为元素分配内存和基于索引等访问项目列表。这些类创建Object类的对象集合,它是C#中所有数据类型的基类。

各种集合类及其用法

以下是System.Collection命名空间的各种常用类。 单击以下链接以检查其详细信息。

Sr.No. 类别与描述和用途
1 ArrayList

它表示可以单独indexed的对象的有序集合。

它基本上是数组的替代品。 但是,与数组不同,您可以使用index在指定位置的列表中添加和删除项目,并且数组会自动调整其大小。 它还允许动态内存分配,添加,搜索和排序列表中的项目。

2 Hashtable

它使用key来访问集合中的元素。

当您需要使用密钥访问元素时,将使用哈希表,并且您可以识别有用的键值。 哈希表中的每个项都有一个key/value对。 该键用于访问集合中的项目。

3 SortedList

它使用keyindex来访问列表中的项目。

排序列表是数组和哈希表的组合。 它包含可以使用键或索引访问的项目列表。 如果使用索引访问项目,则它是ArrayList,如果使用键访问项目,则它是Hashtable。 项目集合始终按键值排序。

4 Stack

它代表了一个last-in, first out的对象集合。

当您需要后进先出的项目访问时使用它。 当你在列表中添加一个项目时,它被称为pushing项目,当你删除它时,它被称为popping项目。

5 Queue

它代表了first-in, first out的对象集合。

当您需要先进先出的物品时,可以使用它。 当您在列表中添加项目时,它将被称为enqueue ,当您删除项目时,它将被称为deque

6 BitArray

它表示使用值1和0的binary representation表示的数组。

它在您需要存储位但未提前知道位数时使用。 您可以使用从零开始的integer index来访问BitArray集合中的项目。

C# - Generics

Generics允许您在类或方法中定义编程元素的数据类型的规范,直到它实际在程序中使用。 换句话说,泛型允许您编写可以使用任何数据类型的类或方法。

您可以使用数据类型的替换参数编写类或方法的规范。 当编译器遇到类的构造函数或方法的函数调用时,它会生成处理特定数据类型的代码。 一个简单的例子将有助于理解这个概念 -

using System;
using System.Collections.Generic;
namespace GenericApplication {
   public class MyGenericArray<T> {
      private T[] array;
      public MyGenericArray(int size) {
         array = new T[size + 1];
      }
      public T getItem(int index) {
         return array[index];
      }
      public void setItem(int index, T value) {
         array[index] = value;
      }
   }
   class Tester {
      static void Main(string[] args) {
         //declaring an int array
         MyGenericArray<int> intArray = new MyGenericArray<int>(5);
         //setting values
         for (int c = 0; c < 5; c++) {
            intArray.setItem(c, c*5);
         }
         //retrieving the values
         for (int c = 0; c < 5; c++) {
            Console.Write(intArray.getItem(c) + " ");
         }
         Console.WriteLine();
         //declaring a character array
         MyGenericArray<char> charArray = new MyGenericArray<char>(5);
         //setting values
         for (int c = 0; c < 5; c++) {
            charArray.setItem(c, (char)(c+97));
         }
         //retrieving the values
         for (int c = 0; c< 5; c++) {
            Console.Write(charArray.getItem(c) + " ");
         }
         Console.WriteLine();
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

0 5 10 15 20
a b c d e

泛型的特征

泛型是一种通过以下方式丰富程序的技术 -

  • 它可以帮助您最大化代码重用,类型安全性和性能。

  • 您可以创建泛型集合类。 .NET Framework类库在System.Collections.Generic命名空间中包含几个新的泛型集合类。 您可以使用这些通用集合类而不是System.Collections命名空间中的集合类。

  • 您可以创建自己的通用接口,类,方法,事件和委托。

  • 您可以创建约束的通用类,以允许访问特定数据类型的方法。

  • 您可以通过反射获得有关在运行时在通用数据类型中使用的类型的信息。

通用方法

在前面的例子中,我们使用了泛型类; 我们可以使用类型参数声明泛型方法。 以下计划说明了这一概念 -

using System;
using System.Collections.Generic;
namespace GenericMethodAppl {
   class Program {
      static void Swap<T>(ref T lhs, ref T rhs) {
         T temp;
         temp = lhs;
         lhs = rhs;
         rhs = temp;
      }
      static void Main(string[] args) {
         int a, b;
         char c, d;
         a = 10;
         b = 20;
         c = 'I';
         d = 'V';
         //display values before swap:
         Console.WriteLine("Int values before calling swap:");
         Console.WriteLine("a = {0}, b = {1}", a, b);
         Console.WriteLine("Char values before calling swap:");
         Console.WriteLine("c = {0}, d = {1}", c, d);
         //call swap
         Swap<int>(ref a, ref b);
         Swap<char>(ref c, ref d);
         //display values after swap:
         Console.WriteLine("Int values after calling swap:");
         Console.WriteLine("a = {0}, b = {1}", a, b);
         Console.WriteLine("Char values after calling swap:");
         Console.WriteLine("c = {0}, d = {1}", c, d);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Int values before calling swap:
a = 10, b = 20
Char values before calling swap:
c = I, d = V
Int values after calling swap:
a = 20, b = 10
Char values after calling swap:
c = V, d = I

通用代表

您可以使用类型参数定义通用委托。 例如 -

delegate T NumberChanger<T>(T n);

以下示例显示了此委托的使用 -

using System;
using System.Collections.Generic;
delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl {
   class TestDelegate {
      static int num = 10;
      public static int AddNum(int p) {
         num += p;
         return num;
      }
      public static int MultNum(int q) {
         num *= q;
         return num;
      }
      public static int getNum() {
         return num;
      }
      static void Main(string[] args) {
         //create delegate instances
         NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
         NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);
         //calling the methods using the delegate objects
         nc1(25);
         Console.WriteLine("Value of Num: {0}", getNum());
         nc2(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Value of Num: 35
Value of Num: 175

C# - Anonymous Methods

我们讨论了代理用于引用与委托具有相同签名的任何方法。 换句话说,您可以使用该委托对象调用委托可以引用的方法。

Anonymous methods提供了一种将代码块作为委托参数传递的技术。 匿名方法是没有名称的方法,只是正文。

您不需要在匿名方法中指定返回类型; 它是从方法体内的return语句推断出来的。

编写匿名方法

使用delegate关键字创建委托实例来声明匿名方法。 例如,

delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x) {
   Console.WriteLine("Anonymous Method: {0}", x);
};

代码块Console.WriteLine("Anonymous Method: {0}", x); 是匿名方法的主体。

可以使用匿名方法以及命名方法以相同方式调用委托,即通过将方法参数传递给委托对象。

例如,

nc(10);

例子 (Example)

以下示例演示了该概念 -

using System;
delegate void NumberChanger(int n);
namespace DelegateAppl {
   class TestDelegate {
      static int num = 10;
      public static void AddNum(int p) {
         num += p;
         Console.WriteLine("Named Method: {0}", num);
      }
      public static void MultNum(int q) {
         num *= q;
         Console.WriteLine("Named Method: {0}", num);
      }
      public static int getNum() {
         return num;
      }
      static void Main(string[] args) {
         //create delegate instances using anonymous method
         NumberChanger nc = delegate(int x) {
            Console.WriteLine("Anonymous Method: {0}", x);
         };
         //calling the delegate using the anonymous method 
         nc(10);
         //instantiating the delegate using the named methods 
         nc =  new NumberChanger(AddNum);
         //calling the delegate using the named methods 
         nc(5);
         //instantiating the delegate using another named methods 
         nc =  new NumberChanger(MultNum);
         //calling the delegate using the named methods 
         nc(2);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Anonymous Method: 10
Named Method: 15
Named Method: 30

C# - Unsafe Codes

当C#被unsafe修饰符标记时,C#允许在代码块的函数中使用指针变量。 unsafe code或非托管代码是使用pointer变量的代码块。

Note - 要在codingground执行本章中提到的程序,请在Project 》》 Compile Options 》》 Compilation Command设置编译选项。

mcs *.cs -out:main.exe -unsafe"

Pointers

pointer是一个变量,其值是另一个变量的地址,即存储器位置的直接地址。 与任何变量或常量类似,您必须先声明指针,然后才能使用它来存储任何变量地址。

指针声明的一般形式是 -

type *var-name;

以下是有效的指针声明 -

int    *ip;    /* pointer to an integer */
double *dp;    /* pointer to a double */
float  *fp;    /* pointer to a float */
char   *ch     /* pointer to a character */

以下示例说明了使用不安全修饰符在C#中使用指针 -

using System;
namespace UnsafeCodeApplication {
   class Program {
      static unsafe void Main(string[] args) {
         int var = 20;
         int* p = &var;
         Console.WriteLine("Data is: {0} ",  var);
         Console.WriteLine("Address is: {0}",  (int)p);
         Console.ReadKey();
      }
   }
}

当上面的代码编译并执行时,它会产生以下结果 -

Data is: 20
Address is: 99215364

您也可以将代码的一部分声明为不安全,而不是将整个方法声明为不安全。 以下部分中的示例显示了这一点。

使用指针检索数据值

您可以使用ToString()方法检索存储在指针变量引用的位置的数据。 以下示例演示了这一点 -

using System;
namespace UnsafeCodeApplication {
   class Program {
      public static void Main() {
         unsafe {
            int var = 20;
            int* p = &var;
            Console.WriteLine("Data is: {0} " , var);
            Console.WriteLine("Data is: {0} " , p->ToString());
            Console.WriteLine("Address is: {0} " , (int)p);
         }
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Data is: 20
Data is: 20
Address is: 77128984

将指针作为参数传递给方法

您可以将指针变量作为参数传递给方法。 以下示例说明了这一点 -

using System;
namespace UnsafeCodeApplication {
   class TestPointer {
      public unsafe void swap(int* p, int *q) {
         int temp = *p;
         *p = *q;
         *q = temp;
      }
      public unsafe static void Main() {
         TestPointer p = new TestPointer();
         int var1 = 10;
         int var2 = 20;
         int* x = &var1;
         int* y = &var2;
         Console.WriteLine("Before Swap: var1:{0}, var2: {1}", var1, var2);
         p.swap(x, y);
         Console.WriteLine("After Swap: var1:{0}, var2: {1}", var1, var2);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Before Swap: var1: 10, var2: 20
After Swap: var1: 20, var2: 10

使用指针访问数组元素

在C#中,数组名称和指向与数组数据相同的数据类型的指针不是相同的变量类型。 例如,int * p和int [] p不是同一类型。 你可以递增指针变量p,因为它没有在内存中修复,但是数组地址在内存中是固定的,你不能增加它。

因此,如果您需要使用指针变量访问数组数据,就像我们传统上用C或C ++(请检查: C指针 )那样,您需要使用fixed关键字修复指针。

以下示例演示了这一点 -

using System;
namespace UnsafeCodeApplication {
   class TestPointer {
      public unsafe static void Main() {
         int[]  list = {10, 100, 200};
         fixed(int *ptr = list)
         /* let us have array address in pointer */
         for ( int i = 0; i < 3; i++) {
            Console.WriteLine("Address of list[{0}]={1}",i,(int)(ptr + i));
            Console.WriteLine("Value of list[{0}]={1}", i, *(ptr + i));
         }
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

Address of list[0] = 31627168
Value of list[0] = 10
Address of list[1] = 31627172
Value of list[1] = 100
Address of list[2] = 31627176
Value of list[2] = 200

编译不安全代码

要编译不安全的代码,必须使用命令行编译器指定/unsafe命令行开关。

例如,要从命令行编译包含不安全代码的名为prog1.cs的程序,请输入命令 -

csc /unsafe prog1.cs

如果您使用的是Visual Studio IDE,则需要在项目属性中启用不安全的代码。

要做到这一点 -

  • 双击解决方案资源管理器中的属性节点打开project properties

  • 单击“ Build选项卡。

  • 选择“ Allow unsafe code ”选项。

C# - Multithreading

thread被定义为程序的执行路径。 每个线程定义一个独特的控制流。 如果您的应用程序涉及复杂且耗时的操作,那么设置不同的执行路径或线程通常很有帮助,每个线程执行特定的工作。

线程是lightweight processes 。 使用线程的一个常见示例是现代操作系统的并发编程的实现。 线程的使用可以节省CPU周期的浪费并提高应用程序的效率。

到目前为止,我们编写了程序,其中单个线程作为单个进程运行,该进程是应用程序的运行实例。 但是,这样应用程序可以一次执行一个作业。 为了使它一次执行多个任务,可以将其划分为更小的线程。

线程生命周期

线程的生命周期在创建System.Threading.Thread类的对象时开始,在线程终止或完成执行时结束。

以下是线程生命周期中的各种状态 -

  • The Unstarted State - 创建线程实例但未调用Start方法的情况。

  • The Ready State - 线程准备运行并等待CPU周期的情况。

  • The Not Runnable State - 线程不可执行,何时

    • 已经调用了睡眠方法
    • 等待方法已被调用
    • 被I/O操作阻止
  • The Dead State - 线程完成执行或中止的情况。

主线程

在C#中, System.Threading.Thread类用于处理线程。 它允许在多线程应用程序中创建和访问各个线程。 在进程中执行的第一个线程称为main线程。

当C#程序开始执行时,将自动创建主线程。 使用Thread类创建的Thread称为主线程的子线程。 您可以使用Thread类的CurrentThread属性访问线程。

以下程序演示了主线程执行 -

using System;
using System.Threading;
namespace MultithreadingApplication {
   class MainThreadProgram {
      static void Main(string[] args) {
         Thread th = Thread.CurrentThread;
         th.Name = "MainThread";
         Console.WriteLine("This is {0}", th.Name);
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

This is MainThread

线程类的属性和方法

下表显示了Thread类的一些最常用的properties -

Sr.No. 财产和描述
1

CurrentContext

获取线程正在执行的当前上下文。

2

CurrentCulture

获取或设置当前线程的区域性。

3

CurrentPrinciple

获取或设置线程的当前主体(用于基于角色的安全性)。

4

CurrentThread

获取当前正在运行的线程。

5

CurrentUICulture

获取或设置资源管理器用于在运行时查找特定于文化的资源的当前区域性。

6

ExecutionContext

获取一个ExecutionContext对象,该对象包含有关当前线程的各种上下文的信息。

7

IsAlive

获取一个值,该值指示当前线程的执行状态。

8

IsBackground

获取或设置一个值,该值指示线程是否为后台线程。

9

IsThreadPoolThread

获取一个值,该值指示线程是否属于托管线程池。

10

ManagedThreadId

获取当前托管线程的唯一标识符。

11

Name

获取或设置线程的名称。

12

Priority

获取或设置一个值,该值指示线程的调度优先级。

13

ThreadState

获取包含当前线程状态的值。

下表显示了Thread类中一些最常用的methods -

Sr.No. 方法和描述
1

public void Abort()

在调用它的线程中引发ThreadAbortException,以开始终止线程的过程。 调用此方法通常会终止该线程。

2

public static LocalDataStoreSlot AllocateDataSlot()

在所有线程上分配一个未命名的数据槽。 为了获得更好的性能,请使用标有ThreadStaticAttribute属性的字段。

3

public static LocalDataStoreSlot AllocateNamedDataSlot(string name)

在所有线程上分配命名数据槽。 为了获得更好的性能,请使用标有ThreadStaticAttribute属性的字段。

4

public static void BeginCriticalRegion()

通知主机执行即将进入代码区域,其中线程中止或未处理异常的影响可能危及应用程序域中的其他任务。

5

public static void BeginThreadAffinity()

通知主机托管代码即将执行依赖于当前物理操作系统线程标识的指令。

6

public static void EndCriticalRegion()

通知主机执行即将进入代码区域,其中线程中止或未处理异常的影响仅限于当前任务。

7

public static void EndThreadAffinity()

通知主机托管代码已完成执行依赖于当前物理操作系统线程标识的指令。

8

public static void FreeNamedDataSlot(string name)

消除进程中所有线程的名称和插槽之间的关联。 为了获得更好的性能,请使用标有ThreadStaticAttribute属性的字段。

9

public static Object GetData(LocalDataStoreSlot slot)

从当前线程的当前域中的当前线程的指定槽中检索值。 为了获得更好的性能,请使用标有ThreadStaticAttribute属性的字段。

10

public static AppDomain GetDomain()

返回当前线程正在运行的当前域。

11

public static AppDomain GetDomainID()

返回唯一的应用程序域标识符

12

public static LocalDataStoreSlot GetNamedDataSlot(string name)

查找命名数据槽。 为了获得更好的性能,请使用标有ThreadStaticAttribute属性的字段。

13

public void Interrupt()

中断处于WaitSleepJoin线程状态的线程。

14

public void Join()

阻塞调用线程直到线程终止,同时继续执行标准COM和SendMessage抽取。 此方法具有不同的重载形式。

15

public static void MemoryBarrier()

按如下方式同步内存访问:执行当前线程的处理器无法重新排序指令,使得在调用MemoryBarrier之前的内存访问在对MemoryBarrier的调用之后的内存访问之后执行。

16

public static void ResetAbort()

取消当前线程请求的中止。

17

public static void SetData(LocalDataStoreSlot slot, Object data)

为当前运行的线程设置该线程当前域的指定槽中的数据。 为了获得更好的性能,请使用标记为ThreadStaticAttribute属性的字段。

18

public void Start()

开始一个帖子。

19

public static void Sleep(int millisecondsTimeout)

使线程暂停一段时间。

20

public static void SpinWait(int iterations)

导致线程等待iterations参数定义的次数

21

public static byte VolatileRead(ref byte address)

public static double VolatileRead(ref double address)

public static int VolatileRead(ref int address)

public static Object VolatileRead(ref Object address)

读取字段的值。 该值是计算机中任何处理器写入的最新值,无论处理器数量或处理器高速缓存状态如何。 此方法具有不同的重载形式。 上面只给出了一些。

22

public static void VolatileWrite(ref byte address,byte value)

public static void VolatileWrite(ref double address, double value)

public static void VolatileWrite(ref int address, int value)

public static void VolatileWrite(ref Object address, Object value)

立即将值写入字段,以便该值对计算机中的所有处理器可见。 此方法具有不同的重载形式。 上面只给出了一些。

23

public static bool Yield()

使调用线程执行到另一个准备在当前处理器上运行的线程。 操作系统选择要生成的线程。

创建线程

通过扩展Thread类来创建线程。 然后,扩展的Thread类调用Start()方法开始子线程执行。

以下程序演示了这个概念 -

using System;
using System.Threading;
namespace MultithreadingApplication {
   class ThreadCreationProgram {
      public static void CallToChildThread() {
         Console.WriteLine("Child thread starts");
      }
      static void Main(string[] args) {
         ThreadStart childref = new ThreadStart(CallToChildThread);
         Console.WriteLine("In Main: Creating the Child thread");
         Thread childThread = new Thread(childref);
         childThread.Start();
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

In Main: Creating the Child thread
Child thread starts

管理线程

Thread类提供了各种管理线程的方法。

以下示例演示如何使用sleep()方法使线程暂停一段特定时间。

using System;
using System.Threading;
namespace MultithreadingApplication {
   class ThreadCreationProgram {
      public static void CallToChildThread() {
         Console.WriteLine("Child thread starts");
         // the thread is paused for 5000 milliseconds
         int sleepfor = 5000; 
         Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor/1000);
         Thread.Sleep(sleepfor);
         Console.WriteLine("Child thread resumes");
      }
      static void Main(string[] args) {
         ThreadStart childref = new ThreadStart(CallToChildThread);
         Console.WriteLine("In Main: Creating the Child thread");
         Thread childThread = new Thread(childref);
         childThread.Start();
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes

销毁线程

Abort()方法用于销毁线程。

运行时通过抛出ThreadAbortException中止线程。 无法捕获此异常,控件将发送到finally块(如果有)。

以下程序说明了这一点 -

using System;
using System.Threading;
namespace MultithreadingApplication {
   class ThreadCreationProgram {
      public static void CallToChildThread() {
         try {
            Console.WriteLine("Child thread starts");
            // do some work, like counting to 10
            for (int counter = 0; counter <= 10; counter++) {
               Thread.Sleep(500);
               Console.WriteLine(counter);
            }
            Console.WriteLine("Child Thread Completed");
         } catch (ThreadAbortException e) {
            Console.WriteLine("Thread Abort Exception");
         } finally {
            Console.WriteLine("Couldn't catch the Thread Exception");
         }
      }
      static void Main(string[] args) {
         ThreadStart childref = new ThreadStart(CallToChildThread);
         Console.WriteLine("In Main: Creating the Child thread");
         Thread childThread = new Thread(childref);
         childThread.Start();
         //stop the main thread for some time
         Thread.Sleep(2000);
         //now abort the child
         Console.WriteLine("In Main: Aborting the Child thread");
         childThread.Abort();
         Console.ReadKey();
      }
   }
}

编译并执行上述代码时,会产生以下结果 -

In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception 
↑回到顶部↑
WIKI教程 @2018