文章目录
- 1. 基础语法
- 1.1 标识符命名规则
- 1.2 C# 关键字
- 1.3 C#注释
- 2. 数据类型
- 2.1 值类型(Value types)
- 2.2 引用类型(Reference types)
- 2.2.1 对象(Object)类型
- 3.2.2 动态(Dynamic)类型
- 2.2.3 字符串(String)类型
- 2.2.3.1 关于@
- 2.3 指针类型(Pointer types)
- 2.4 数据类型转换
- 2.4.1 内置的类型转换方法
- 2.5 可空类型(Nullable)
- 2.5.1 单问号 ? 与 双问号 ??
- 2.6 数组(Array)
- 2.6.1 声明/初始化/赋值数组
- 2.6.2 访问数组元素
- 2.6.3 使用 foreach 循环遍历数组
- 2.6.4 多维数组
- 2.7 字符串(String)
- 2.7.1 创建 String 对象
- 2.7.2 String 类的属性
- 2.7.3 String 类的方法
- 2.7.* 例程
- 2.7.*.1 比较字符串
- 2.7.*.2 查找字符串中指定的字符串
- 2.7.*.3 获取子字符串(切片)
- 2.7.*.4 拼接字符串
- 2.8 结构体(Struct)
- 2.8.1 定义结构体/结构体变量
- 2.8.2 结构体与类的区别
- 2.9 枚举(Enum)
- 2.10 数据类型转换
- string 相关的转化
- 3. 变量
- 3.1 变量类型转换
- 3.2 强制类型转换
- 3.3 变量作用域
- 3.4 变量修饰符
- 3.4.1 `out`修饰符展示
- 3.4.2 `ref`修饰符展示
- 4. 常量
- 4.1 整型常量
- 4.2 浮点型常量
- 4.3 字符型常量
- 4.4 字符串型常量
- 4.5 常量的定义
- 5. 运算符
- 5.1 算术运算符
- 5.1.1 关于i++与++i
- 5.2 关系运算符
- 5.3 逻辑运算符
- 5.4 位运算符
- 5.5 赋值运算符
- 5.6 其他运算符
- 5.7 运算符优先级
- 6. 三大结构
- 6.1 条件结构
- 6.1.1 switch语句
- 6.1.2 条件运算符 ?:
- 6.2 循环结构
- 6.2.1 for/foreach 循环
- 6.2.2 循环控制语句
1. 基础语法
1.1 标识符命名规则
标识符是用来识别类、变量、函数或任何其它用户定义的项目(即变量名、函数名、类名等)。在 C# 中,类的命名必须遵循如下基本规则:
- 必须以字母、下划线或 @ 开头。第一个字符不能是数字。
- 必须不包含任何嵌入的空格或符号,比如 ? - +! # % ^ & * ( ) [ ] { } . ; : " ’ / \。
- 不能是 C# 关键字。除非它们有一个 @ 前缀。 例如,@if 是有效的标识符,但 if 不是,因为 if 是关键字。
- 必须区分大小写。大写字母和小写字母被认为是不同的字母。
- 不能与C#的类库名称相同。
1.2 C# 关键字
关键字是 C# 编译器预定义的保留字。这些关键字不能用作标识符。有些关键字在代码的上下文中有特殊的意义,如 get
和 set
,这些被称为上下文关键字(Contextual keywords)。
- C#关键字
1.3 C#注释
文档注释只需在方法或类定义的上一行输入///
即可自动生成注释模板。一般文档注释也只用在方法或类上。
// 单行注释
/*
多
行
注
释
*/
///<summary>
///文档注释
///</summary>
2. 数据类型
在 C# 中,变量分为以下几种类型:
- 值类型(Value types)
- 引用类型(Reference types)
- 指针类型(Pointer types)
2.1 值类型(Value types)
值类型数据可以直接分配给其一个值。它们是从类 System.ValueType
中派生的。
被赋值后的值类型变量就包含了数据。比如int、char、float
等数据类型,它们分别存储数字、字符、浮点数。当您声明一个 int
类型的变量时,系统分配内存来存储该变量的值。
- 值类型
2.2 引用类型(Reference types)
引用类型不包含存储在变量中的实际数据,但包含对变量的引用。即它们指向的是一个内存位置。内置的引用类型有:object
、dynamic
和 string
。
- 应用类型
2.2.1 对象(Object)类型
该类型是C# 通用类型系统(Common Type System - CTS)中所有数据类型的最终基类。Object 是 System.Object
类的别名。所以对象(Object)类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。
当一个值类型转换为对象类型时,则被称为装箱;反之,当一个对象类型转换为值类型时,则被称为拆箱。
object obj; // 声明对象类型变量
obj = 100; // 装箱
3.2.2 动态(Dynamic)类型
该类型可存储任何类型的值在动态数据类型变量中。这些变量的类型定义在运行时发生。
动态类型与对象类型相似,但对象类型变量的类型定义是在编译时发生的,而动态类型变量的类型定义是在运行时发生的。
dynamic d = 20; // 声明并初始化动态类型变量
2.2.3 字符串(String)类型
该类型允许给变量分配任何字符串值。字符串(String)类型是System.String
类的别名。它从对象(Object)类型派生的。字符串(String)类型的值可以通过两种形式进行分配:引号""
和 @引号@""
。
String str = "run"; // 声明并初始化字符串类型变量
@"runoob.com"; // @引号字符串
2.2.3.1 关于@
@
叫逐字字符串,其作用如下:
- 可将转义字符
\
当作普通字符对待。 - @ 字符串中可以任意换行,换行符及缩进空格都计算在字符串长度之内。
string str = @"C:\Windows";
等价于:
string str = "C:\\Windows";
string str = @"<script type=""text/javascript"">
<!--
-->
</script>";
2.3 指针类型(Pointer types)
指针类型存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针有相同的功能。
char* cptr; //声明指针变量
int* iptr;
2.4 数据类型转换
C# 中,数据类型转换有两种形式:
- 隐式类型转换:C# 默认的自动的以安全方式进行的转换, 它不会导致数据的丢失。例如,从小的整数类型转换为大的整数类型,从派生类转换为基类。
- 显式类型转换:即强制类型转换。显式转换需要强制转换运算符,强制转换会造成数据的丢失。
using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
namespace TypeConversionApplication
{
class ExplicitConversion
{
static void Main(string[] args)
{
double d = 5673.74;
int i;
i = (int)d; // 强制转换 double 为 int类型
Console.WriteLine(i);
Console.ReadKey();
}
}
}
控制台输出:5673
2.4.1 内置的类型转换方法
方法命 | 功能描述 |
---|---|
ToBoolean | 如果可能的话,把类型转换为布尔型。 |
ToByte | 把类型转换为字节类型。 |
ToChar | 如果可能的话,把类型转换为单个 Unicode 字符类型。 |
ToDateTime | 把类型(整数或字符串类型)转换为 日期-时间 结构。 |
ToDecimal | 把浮点型或整数类型转换为十进制类型。 |
ToDouble | 把类型转换为双精度浮点型。 |
ToInt16 | 把类型转换为 16 位整数类型。 |
ToInt32 | 把类型转换为 32 位整数类型。 |
ToInt64 | 把类型转换为 64 位整数类型。 |
ToSbyte | 把类型转换为有符号字节类型。 |
ToSingle | 把类型转换为小浮点数类型。 |
ToString | 把类型转换为字符串类型。 |
ToType | 把类型转换为指定类型。 |
ToUInt16 | 把类型转换为 16 位无符号整数类型。 |
ToUInt32 | 把类型转换为 32 位无符号整数类型。 |
ToUInt64 | 把类型转换为 64 位无符号整数类型。 |
using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
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();
}
}
}
2.5 可空类型(Nullable)
C# 提供了一个特殊的数据类型,nullable 类型(可空类型),被定义为可空类型的变量允许表示其基础值类型正常范围内的所有值或 null 值。
例如,
Nullable< Int32 >
,读作"可空的 Int32",它可被赋值为 -2,147,483,648 到 2,147,483,647 之间的任意值,也可被赋值为 null 值。类似的,Nullable< bool >
变量可以被赋值为 true 或 false 或 null。
在处理数据库和其他包含可能未赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型的功能特别有用。
例如,数据库中的布尔型字段可以存储值 true 或 false,或该字段也可以未定义,即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?(); // 定义可空的布尔型变量
// 显示值
Console.WriteLine("显示可空类型的值: {0}, {1}, {2}, {3}",
num1, num2, num3, num4);
Console.WriteLine("一个可空的布尔值: {0}", boolval);
Console.ReadLine();
}
}
}
2.5.1 单问号 ? 与 双问号 ??
单问号?
用于对 int,double,bool
等无法直接赋值为 null 的数据类型进行 null 的赋值,即这个数据类型是 Nullable 类型的。
int i; //默认值为0
int? ii; //默认值为null
双问号??
又叫合并运算符,可用于判断一个变量是否为 null ,是则返回一个指定的值。
double? num1 = null;
double? num2 = 3.14157;
double num3;
num3 = num1 ?? 5.34; // num1 如果为空值则返回 5.34,否则返回num1的值
Console.WriteLine("num3 的值: {0}", num3);
num3 = num2 ?? 5.34; // num2 如果为空值则返回 5.34,否则返回num2的值,即3.14157
Console.WriteLine("num3 的值: {0}", num3);
运行结果:
num3 的值: 5.34
num3 的值: 3.14157
2.6 数组(Array)
数组是一个存储相同类型元素的固定大小的有序的集合。
数组是由连续的内存位置组成的。最低的地址对应第一个元素,最高的地址对应最后一个元素。
2.6.1 声明/初始化/赋值数组
数组是一个引用类型,需要使用 new
关键字来创建数组的实例。
声明数组后,内存中不会为其分配内粗。只有当数组被初始化后,才会为其分配内存,此后才能给数组赋值。也可以在声明数组的同时,对数组进行赋值(相当于初始化与赋值同步进行)。
数组之间赋值时,目标和源都会指向相同的内存位置。
double[] balance; // 声明数组
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[] score = marks; // 赋值一个数组变量到另一个数组
2.6.2 访问数组元素
元素是通过带索引的数组名称来访问的。
double salary = balance[9];
2.6.3 使用 foreach 循环遍历数组
using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
namespace ArrayApplication
{
class MyArray
{
static void Main(string[] args)
{
int[] n = new int[10]; /* n 是一个带有 10 个整数的数组 */
/* 初始化数组 n 中的元素 */
for (int i = 0; i < 10; i++)
{
n[i] = i + 100;
}
/* 输出每个数组元素的值 */
foreach (int j in n)
{
int i = j - 100;
Console.WriteLine("Element[{0}] = {1}", i, j);
}
Console.ReadKey();
}
}
}
2.6.4 多维数组
多维数组又称为矩形数组。一个二维数组,在本质上,是一个一维数组的列表。
string [,] names; // 声明一个二维数组
int [ , , ] m; // 声明一个三维数组
- 初始化二维数组:多维数组可以通过在括号内为每行指定值来进行初始化。
int [,] a = new int [3,4] {
{0, 1, 2, 3} , /* 初始化索引号为 0 的行 */
{4, 5, 6, 7} , /* 初始化索引号为 1 的行 */
{8, 9, 10, 11} /* 初始化索引号为 2 的行 */
};
- 访问二维数组元素
int val = a[2,3];
2.7 字符串(String)
在 C# 中,可以像C语言一样使用字符数组来表示字符串,但更常见的做法是使用 string
关键字来声明一个字符串变量。string
关键字是 System.String
类的别名。
2.7.1 创建 String 对象
可以使用以下方法之一来创建 string 对象:
- 通过给 String 变量赋值一个字符串
- 通过使用 String 类构造函数
- 通过使用字符串串联运算符( + )
- 通过检索属性或调用一个返回字符串的方法
- 通过格式化方法来转换一个值或对象为它的字符串表示形式
using System;
namespace StringApplication
{
class Program
{
static void Main(string[] args)
{
//字符串,字符串连接
string fname, lname; // 定义string变量
fname = "an";
lname = "tennin";
string fullname = fname + lname;
Console.WriteLine("Full Name: {0}", fullname);
//通过使用 string 构造函数
char[] letters = { 'H', 'e', 'l', 'l', 'o' }; // 定义并初始化字符数组
string greetings = new string(letters);
Console.WriteLine("Greetings: {0}", greetings);
//方法返回字符串
string[] sarray = { "Hello", "From", "antennin", "Point" }; // 定义并初始化字符串数组
string message = String.Join(" ", sarray); // 使用Join方法插入字符串
Console.WriteLine("Message: {0}", message);
//用于转化值的格式化方法
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);
Console.ReadKey();
}
}
}
运行输出:
Full Name: antennin
Greetings: Hello
Message: Hello From antennin Point
Message: Message sent at 17:58 on 2012年10月10日
2.7.2 String 类的属性
String 类有两个属性:
属性名称 | 描述 |
---|---|
Chars | 在当前 String 对象中获取 Char 对象的指定位置。 |
Length | 在当前的 String 对象中获取字符数。 |
2.7.3 String 类的方法
下面的提供了一些最常用的string方法:
转到函数的定义处即可查看到该函数的重载和官方应用说明。
方法名称 | 描述 |
---|---|
public static int Compare( string strA, string strB ) | 比较两个指定的 string 对象,并返回一个表示它们在排列顺序中相对位置的整数。该方法区分大小写。 |
public static int Compare( string strA, string strB, bool ignoreCase ) | 比较两个指定的 string 对象,并返回一个表示它们在排列顺序中相对位置的整数。但是,如果布尔参数为真时,该方法不区分大小写。 |
public static string Concat( string str0, string str1 ) | 连接两个 string 对象。 |
public static string Concat( string str0, string str1, string str2 ) | 连接三个 string 对象。 |
public static string Concat( string str0, string str1, string str2, string str3 ) | 连接四个 string 对象。 |
public bool Contains( string value ) | 返回一个表示指定 string 对象是否出现在字符串中的值。 |
public static string Copy( string str ) | 创建一个与指定字符串具有相同值的新的 String 对象。 |
public void CopyTo( int sourceIndex, char[] destination, int destinationIndex, int count ) | 从 string 对象的指定位置开始复制指定数量的字符到 Unicode 字符数组中的指定位置。 |
public bool EndsWith( string value ) | 判断 string 对象的结尾是否匹配指定的字符串。 |
public bool Equals( string value ) | 判断当前的 string 对象是否与指定的 string 对象具有相同的值。 |
public static bool Equals( string a, string b ) | 判断两个指定的 string 对象是否具有相同的值。 |
public static string Format( string format, Object arg0 ) | 把指定字符串中一个或多个格式项替换为指定对象的字符串表示形式。 |
public int IndexOf( char value ) | 返回指定 Unicode 字符在当前字符串中第一次出现的索引,索引从 0 开始。 |
public int IndexOf( string value ) | 返回指定字符串在该实例中第一次出现的索引,索引从 0 开始。 |
public int IndexOf( char value, int startIndex ) | 返回指定 Unicode 字符从该字符串中指定字符位置开始搜索第一次出现的索引,索引从 0 开始。 |
public int IndexOf( string value, int startIndex ) | 返回指定字符串从该实例中指定字符位置开始搜索第一次出现的索引,索引从 0 开始。 |
public int IndexOfAny( char[] anyOf ) | 返回某一个指定的 Unicode 字符数组中任意字符在该实例中第一次出现的索引,索引从 0 开始。 |
public int IndexOfAny( char[] anyOf, int startIndex ) | 返回某一个指定的 Unicode 字符数组中任意字符从该实例中指定字符位置开始搜索第一次出现的索引,索引从 0 开始。 |
public string Insert( int startIndex, string value ) | 返回一个新的字符串,其中,指定的字符串被插入在当前 string 对象的指定索引位置。 |
public static bool IsNullOrEmpty( string value ) | 指示指定的字符串是否为 null 或者是否为一个空的字符串。 |
public static string Join( string separator, string[] value ) | 连接一个字符串数组中的所有元素,使用指定的分隔符分隔每个元素。 |
public static string Join( string separator, string[] value, int startIndex, int count ) | 连接接一个字符串数组中的指定位置开始的指定元素,使用指定的分隔符分隔每个元素。 |
public int LastIndexOf( char value ) | 返回指定 Unicode 字符在当前 string 对象中最后一次出现的索引位置,索引从 0 开始。 |
public int LastIndexOf( string value ) | 返回指定字符串在当前 string 对象中最后一次出现的索引位置,索引从 0 开始。 |
public string Remove( int startIndex ) | 移除当前实例中的所有字符,从指定位置开始,一直到最后一个位置为止,并返回字符串。 |
public string Remove( int startIndex, int count ) | 从当前字符串的指定位置开始移除指定数量的字符,并返回字符串。 |
public string Replace( char oldChar, char newChar ) | 把当前 string 对象中,所有指定的 Unicode 字符替换为另一个指定的 Unicode 字符,并返回新的字符串。 |
public string Replace( string oldValue, string newValue ) | 把当前 string 对象中,所有指定的字符串替换为另一个指定的字符串,并返回新的字符串。 |
public String[] Split(String[] separator, StringSplitOptions options); | 基于数组separator中的字符串将字符串拆分为多个子字符串。 |
public String[] Split(String[] separator, int count, StringSplitOptions options); | 基于数组separator中的字符将一个字符串拆分成最大数量的子字符串。 |
public bool StartsWith( string value ) | 判断字符串实例的开头是否匹配指定的字符串。 |
public char[] ToCharArray() | 返回一个带有当前 string 对象中所有字符的 Unicode 字符数组。 |
public char[] ToCharArray( int startIndex, int length ) | 返回一个带有当前 string 对象中所有字符的 Unicode 字符数组,从指定的索引开始,直到指定的长度为止。 |
public string ToLower() | 把字符串转换为小写并返回。 |
public string ToUpper() | 把字符串转换为大写并返回。 |
public string Trim() | 移除当前 String 对象中的所有前导空白字符和后置空白字符。 |
2.7.* 例程
2.7.*.1 比较字符串
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() ;
}
}
}
- 也可以通过运算符比较两个字符串
using System;
namespace StringApplication
{
class StringProg
{
static void Main(string[] args)
{
string str1 = "This is test";
string str2 = "This is text";
if (str1 == str2)
{
Console.WriteLine(str1 + " and " + str2 + " are equal.");
}
else if(str1 != str2)
{
Console.WriteLine(str1 + " and " + str2 + " are not equal.");
}
Console.ReadKey() ;
}
}
}
2.7.*.2 查找字符串中指定的字符串
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();
}
}
}
2.7.*.3 获取子字符串(切片)
using System;
namespace StringApplication
{
class StringProg
{
static void Main(string[] args)
{
string str = "Last night I dreamt of San";
Console.WriteLine(str);
string substr = str.Substring(23); // 获取子字符串
Console.WriteLine(substr);
Console.ReadKey();
}
}
}
2.7.*.4 拼接字符串
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);
Console.ReadKey();
}
}
}
2.8 结构体(Struct)
在 C# 中,结构体属于值类型数据结构。它可以存储各种数据类型的相关数据。这一点与C/C++原理相近。
2.8.1 定义结构体/结构体变量
在 C# 中的结构体与 C/C++ 中的结构体不同的地方为:
- 结构可带有方法、字段、索引、属性、运算符方法和事件。
- 结构可定义构造函数,但不能定义析构函数。但是,您不能为结构定义无参构造函数。无参构造函数(默认)是自动定义的,且不能被改变。
- 与类不同,结构不能继承其他的结构或类。
- 结构不能作为其他结构或类的基础结构。
- 结构可实现一个或多个接口。
- 结构成员不能指定为 abstract、virtual 或 protected。
- 当您使用 New 操作符创建一个结构对象时,会调用适当的构造函数来创建结构。与类不同,结构可以不使用 New 操作符即可被实例化。
-如果不使用 New 操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才被使用。
using System;
using System.Text;
// 定义结构体
struct Books
{
public string title;
public string author;
public string subject;
public int book_id;
};
public class testStructure
{
public static void Main(string[] args)
{
// C#中定义结构体变量不需要前面加关键字 struct
Books Book1; /* 声明结构体变量 Book1,类型为 Books */
Books Book2; /* 声明结构体变量 Book2,类型为 Books */
/* book 1 详述 */
Book1.title = "C Programming";
Book1.author = "Nuha Ali";
Book1.subject = "C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 详述 */
Book2.title = "Telecom Billing";
Book2.author = "Zara Ali";
Book2.subject = "Telecom Billing Tutorial";
Book2.book_id = 6495700;
/* 打印 Book1 信息 */
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);
/* 打印 Book2 信息 */
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();
}
}
2.8.2 结构体与类的区别
类和结构有以下几个基本的不同点:
- 类是引用类型,结构是值类型。
- 结构不支持继承。
- 结构不能声明默认的构造函数。
using System;
using System.Text;
struct Books
{
private string title;
private string author;
private string subject;
private int book_id;
public void setValues(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(); /* 声明 Book1,类型为 Books */
Books Book2 = new Books(); /* 声明 Book2,类型为 Books */
/* book 1 详述 */
Book1.setValues("C Programming",
"Nuha Ali", "C Programming Tutorial",6495407);
/* book 2 详述 */
Book2.setValues("Telecom Billing",
"Zara Ali", "Telecom Billing Tutorial", 6495700);
/* 打印 Book1 信息 */
Book1.display();
/* 打印 Book2 信息 */
Book2.display();
Console.ReadKey();
}
}
2.9 枚举(Enum)
枚举是一组命名整型常量。与结构体一样,C# 的枚举属于值类型。即枚举包含自己的值,且不能继承或传递继承。
using System;
public class EnumTest
{
enum Day { Sun, Mon, Tue, Wed, Thu, Fri, Sat }; // 定义枚举
static void Main()
{
int x = (int)Day.Sun;
int y = (int)Day.Fri;
Console.WriteLine("Sun = {0}", x);
Console.WriteLine("Fri = {0}", y);
}
}
2.10 数据类型转换
string 相关的转化
int
转string
int a = 15;
string s1 = a.ToString(); // 方法1
string s2 = Convert.ToString(a); // 方法2
3. 变量
一个变量是一个供程序操作的内存区的名字。在 C# 中,每个变量都有一个指定的类型,此类型决定了该变量的内存大小和布局。
C# 中提供的基本的变量类型可分为以下几类:
类型 | 举例 |
---|---|
整数类型 | sbyte、byte(0-255)、short(-32768-32767)、ushort、int(-2147483648-2147483647)、uint、long、ulong 和 char |
浮点型 | float 和 double(double是所有类型中范围最大的) |
十进制类型 | decimal,它也是浮点型的一种,精度比float和double高,float和double总是存在精度损失,而decimal则不会 |
布尔类型 | true 或 false |
字符串类型 | string、char |
空类型 | null,可为空值的数据类型 |
// 变量定义
int i, j, k;
char c, ch;
float f, salary;
double d;
// 变量定义并初始化
int i = 100;
float f = 1.1F; // 单精度浮点型数值必须加后缀F
double d = 1.1;
decimal de = 1.1M; // 十进制类型数值必须加后缀M
string s = "hellow world!"; // 字符串使用""包住
char c = 'h'; // 字符使用''包住
// null
string st = "hellow world!";
st = null;
st = "";
//以上都表示将字符串st清空,但不同的是null表示将字符串彻底清空,而""表示将一个空的字符串赋值给字符串st(空字符串也是一个字符串)
//变量类型中,只有string是可以为null的
3.1 变量类型转换
- 类型范围小的变量可赋值给类型范围大的变量,反之则报错。
// 变量定义
int i =0;
long l =0;
l=i; // 允许
i=l; // 报错
- 浮点型的转换只有float赋值给double一种。
3.2 强制类型转换
3.3 变量作用域
- 在函数内定义的局部变量只在其函数内作用。
- 在类内函数外定义的变量可用在类内的函数总,但当该函数中存在同名变量时,则报错。
3.4 变量修饰符
- 无修饰符:即变量类型无修饰符修饰。
out
:传入参数必须由被调用的方法赋值修改,以此按引用传递。其原理近似于一个指针。ref
:传入参数在被方法调用前必须赋有初值,并输入参数在被调用的方法内可被修改也可不修改(数据是按引用传递的)。
out
和ref
的区别:out
修饰的参数必须在方法内进行修改,而ref
无该要求。- 调用方法的输入参数若是局部变量,
out
修饰的输入参数可无初始值,因为out
一定会在方法内对其赋值。而ref
修饰的输入参数只有在实参有初始值时才能被调用,因为ref
不一定在方法内对其赋值。
3.4.1 out
修饰符展示
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string message = "hellow world!";
MessageBox.Show(message);
SendMesage(out message);
MessageBox.Show(message);
}
public void SendMesage(out string message) // 输入变量为指向message变量的内存地址
{
message = "世界你好!"; // 该内存地址的值发生改变,out引用的参数必须在函数内进行赋值,这一点与ref不同
MessageBox.Show(message);
}
}
}
运行结果:输出一次hellow world!,两次世界你好!
- 另一种用法:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
SendMesage(out string message); // 在调用函数时定义变量,输入参数允许没有初始值,这一点与ref不同
MessageBox.Show(message);
}
public void SendMesage(out string message)
{
message = "世界你好!";
MessageBox.Show(message);
}
}
}
3.4.2 ref
修饰符展示
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string message = "hellow world!";
SendMesage(ref message); // ref的输入参数必须要有初始值
MessageBox.Show(message);
}
public void SendMesage(ref string message)
{
message = "世界你好!"; // ref的传入参数,在函数内可被修改,也可不被修改,这一点与out不同
MessageBox.Show(message);
}
}
}
4. 常量
常量是固定值,在程序执行期间不会也不能改变。常量可以是任何基本数据类型,比如整数常量、浮点常量、字符常量或者字符串常量,还有枚举常量。
4.1 整型常量
整数常量可以是十进制、八进制或十六进制的常量。
其前缀指定了其进制类型:0x 或 0X 表示十六进制,0 表示八进制,没有前缀则表示十进制。
其后缀制定了其数据类型,可以是 U 或 L ,其中,U 和 L 分别表示 unsigned 和 long。可以多个后缀以任意顺序进行组合。后缀部分大小写。
212 /* 合法 */
215u /* 合法 */
0xFeeL /* 合法 */
078 /* 非法:8 不是一个八进制数字 */
032UU /* 非法:不能重复后缀 */
85 /* 十进制 */
0213 /* 八进制 */
0x4b /* 十六进制 */
30 /* int */
30u /* 无符号 int */
30l /* long */
30ul /* 无符号 long */
4.2 浮点型常量
一个浮点常量是由整数部分、小数点、小数部分和指数部分组成。可使用小数形式或指数形式来表示浮点常量。
3.14159 /* 合法 */
314159E-5L /* 合法 */
210f /* 非法:没有小数或指数 */
.e55 /* 非法:缺少整数或小数 */
使用小数形式表示时,必须包含小数点或指数或同时包含两者。
使用指数形式表示时,必须包含整数部分或小数部分或同时包含两者。
4.3 字符型常量
字符常量括在单引号里,如'x'
。一个字符常量可以是一个普通字符(如 'x'
)或一个转义序列(如 '\t'
)或一个通用字符(如 '\u02C0'
)。
在 C# 中有一些特定的字符,当它们的前面带有反斜杠时有特殊的意义,可用于表示换行符(\n
)或制表符 tab(\t
)。
转义序列码有:
转义序列 | 含义 |
---|---|
| \ 字符 | |
’ | ’ 字符 |
" | " 字符 |
? | ? 字符 |
\a | Alert 或 bell |
\b | 退格键(Backspace) |
\f | 换页符(Form feed) |
\n | 换行符(Newline) |
\r | 回车 |
\t | 水平制表符 tab |
\v | 垂直制表符 tab |
\ooo | 一到三位的八进制数 |
\xhh . . . | 一个或多个数字的十六进制数 |
4.4 字符串型常量
字符串常量括在双引号 ""
里,或括在 @""
里。字符串常量包含的字符与字符常量相似,可以是:普通字符、转义序列和通用字符
字符串常量可把一个很长的行拆成多个行,可以使用空格分隔各个部分。
string a = "hello, world";
string b = @"hello, world";
string j = @"one
two
three";
4.5 常量的定义
使用 关键字const
来定义常量 。
const int c1 = 5;
5. 运算符
C# 内置的运算符分类如下:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 其他运算符
5.1 算术运算符
运算符 | 描述 |
---|---|
+ | 把两个操作数相加 |
- | 从第一个操作数中减去第二个操作数 |
* | 把两个操作数相乘 |
/ | 分子除以分母 |
% | 取模运算符,整除后的余数 |
++ | 自增运算符,整数值增加 1 |
– | 自减运算符,整数值减少 1 |
5.1.1 关于i++与++i
与C、C++语法同理:
c = i++;
:先将 i赋值给 c,再对 i 进行自增运算。c = ++i;
:先将 i 进行自增运算,再将 i 赋值给 c 。
5.2 关系运算符
运算符 | 描述 |
---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为真。 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 |
5.3 逻辑运算符
运算符 | 描述 |
---|---|
&& | 逻辑与运算符。如果两个操作数都非零,则条件为真。 |
` | |
! | 逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 |
5.4 位运算符
运算符作用于逐位执行操作。
以下假设 A = 0011 1100、B = 0000 1101
运算符 | 描述 | 实例 |
---|---|---|
& | 位与,如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中。 | (A & B) 将得到 12,即为 0000 1100 |
` | ` | 位或,如果存在于任一操作数中,二进制 OR 运算符复制一位到结果中。 |
^ | 异或运算符,当两个二进制数不同时,结果为1。 | (A ^ B) 将得到 49,即为 0011 0001 |
~ | 按位取反运算符是一元运算符,即0变成1,1变成0,包括符号位。 | (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
<< | 二进制左移运算符。左操作数的值向左移动右操作数指定的位数。 | A << 2 将得到 240,即为 1111 0000 |
>> | 二进制右移运算符。左操作数的值向右移动右操作数指定的位数。 | A >> 2 将得到 15,即为 0000 1111 |
5.5 赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
<<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
>>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
&= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
` | =` | 按位或且赋值运算符 |
5.6 其他运算符
运算符 | 描述 | 实例 |
---|---|---|
sizeof() | 返回数据类型的大小。 | sizeof(int),将返回 4. |
typeof() | 返回 class 的类型。 | typeof(StreamReader); |
& | 返回变量的地址。 | &a; 将得到变量的实际地址。 |
* | 变量的指针。 | *a; 将指向一个变量。 |
?: | 条件表达式 | 如果条件为真 ? 则为 X : 否则为 Y |
is | 判断对象是否为某一类型,返回值为bool类型 | If( Ford is Car) // 检查 Ford 是否是 Car 类的一个对象。 |
as | 强制转换,即使转换失败也不会抛出异常。 | Object obj = new StringReader(“Hello”); StringReader r = obj as StringReader; |
x.m | 成员访问 | |
x{…} | 数组和索引器访问 | |
new T(…) | 对象和委托创建 | |
new T(…){…} | 使用初始值设定项创建对象 | |
new{…} | 匿名对象初始值设定 | |
new T{…} | 数组创建 | |
(T)x | 将x显式转换为T |
5.7 运算符优先级
下表按运算符优先级从高到低列出各个运算符,在表达式中,较高优先级的运算符会优先被计算。
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () 、[] 、-> 、.、 ++、 - - | 从左到右 |
一元 | + 、-、 !、 ~、 ++、 - -、 (type)*、 &、 sizeof,一元表达式即其运算的变量只能有一个 | 从右到左 |
乘除 | * 、/、 % | 从左到右 |
加减 | + 、- | 从左到右 |
移位 | << 、>> | 从左到右 |
关系 | < 、<=、 >、 >= | 从左到右 |
相等 | ==、 != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | ` | ` |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | ` | |
条件 | ?: | 从右到左 |
赋值 | = 、+=、 -=、 *=、 /=、 %=、>>=、 <<=、 &= 、^=、 ` | =` |
逗号 | , | 从左到右 |
6. 三大结构
与C语言的三大结构相同:顺序、选择、循环。顺序结构略讲。
6.1 条件结构
语句 | 描述 |
---|---|
if 语句 | 一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。 |
if…else 语句 | 一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。 |
嵌套 if 语句 | 您可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。 |
switch 语句 | 一个 switch 语句允许测试一个变量等于多个值时的情况。 |
嵌套 switch 语句 | 您可以在一个 switch 语句内使用另一个 switch 语句。 |
6.1.1 switch语句
语法:
switch(expression){
case constant-expression :
statement(s);
break;
case constant-expression :
statement(s);
break;
/* 可以有任意数量的 case 语句 */
default : /* 可选的 */
statement(s);
break;
}
其中:
- switch 语句中的expression 必须是一个整型或枚举类型或是一个 class 类型,其中 class 有一个单一的转换函数将其转换为整型或枚举类型。
- case 的 constant-expression 必须与 switch 中的变量具有相同的数据类型,且必须是一个常量。
- 当遇到 break 语句时,switch语句终止,控制流将跳转到 switch 语句后的下一行。
- 不是每一个 case 都需要包含 break。如果 case 语句为空,则可以不包含 break,控制流将会继续后续的 case,直到遇到 break 为止。
- 一个 switch 语句可以有一个可选的 default case,必须出现在 switch 的结尾。default case 可用于在上面所有 case 都不为真时执行的一个任务。default case 中的 break 语句不是必需的。
流程图:
6.1.2 条件运算符 ?:
条件运算符 ?:
,可用来替代 if...else
语句。
Exp1 ? Exp2 : Exp3; // 其中Expx为表达式
该语句的结果取决于Exp1的值:
- 如果 Exp1 为真,则计算 Exp2 的值,结果即为整个
?:
表达式的值。 - 如果 Exp1 为假,则计算 Exp3 的值,结果即为整个
?:
表达式的值。
6.2 循环结构
循环类型 | 描述 |
---|---|
while 循环 | 当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。 |
for/foreach 循环 | 多次执行一个语句序列,简化管理循环变量的代码。 |
do…while 循环 | 除了它是在循环主体结尾测试条件外,其他与 while 语句类似。 |
嵌套循环 | 可以在 while、for 或 do…while 循环内使用一个或多个循环。 |
6.2.1 for/foreach 循环
// for语句语法例程
for (int a = 10; a < 20; a = a + 1)
{
Console.WriteLine("a 的值: {0}", a);
}
int[] fibarray = new int[] { 0, 1, 1, 2, 3, 5, 8, 13 };
foreach (int element in fibarray)
{
System.Console.WriteLine(element);
}
System.Console.WriteLine();
输出:
0
1
1
2
3
5
8
13
Foreach 语句官方文档
C# 中 foreach 遍历的用法
6.2.2 循环控制语句
控制语句 | 描述 |
---|---|
break 语句 | 终止循环或 switch 语句,程序流继续执行紧接着循环或 switch 的下一条语句。即跳出当前循环语句 |
continue 语句 | 跳出语句的本次循环 |