C#理论 —— 基础语法、数据类型、变量、常量、操作符、三大结构

本文围绕C#展开,介绍了其基础元素、标识符命名规则、关键字等内容。详细阐述了C#的五大数据类型,包括值类型、引用类型等,还说明了数据类型转换、可空类型等知识。此外,讲解了常量、操作符以及条件和循环等三大结构。

文章目录

1. 基础&综述


1.1 构成C#语音的基本元素

  • 关键字
  • 操作符
  • 标识符
  • 标点符号
  • 文本
  • 注释与空白

1.2 标识符命名规则

标识符是用来识别类、变量、函数或任何其它用户定义的项目(即变量名、函数名、类名等)。在 C# 中,类的命名必须遵循如下基本规则:

  • 必须以字母、下划线或 @ 开头。第一个字符不能是数字;
  • 必须不包含任何嵌入的空格或符号,比如 ? - +! # % ^ & * ( ) [ ] { } . ; : " ’ / \;
  • 不能是 C# 关键字。除非它们有一个 @ 前缀。 例如,@if 是有效的标识符,但 if 不是,因为 if 是关键字;
  • 必须区分大小写。大写字母和小写字母被认为是不同的字母;
  • 不能与C#的类库名称同名;

一般命名空间、类名、方法名用帕斯卡命名法(MyVariable,所有单词首字母全大写),其他用骆驼命名法(myVariable,第一个单词首字母小写,其他大写)

1.3 关键字

关键字是 C# 编译器预定义的保留字。这些关键字不能用作标识符。
在这里插入图片描述在这里插入图片描述

1.3.1 defual

default(T) 关键字用于获取类型 T 的默认值;对于引用类型(如 Form),这个默认值就是 null;

// 下面两条语句功能等价:
Form myForm = default(Form);
Form myForm = null;

1.4 注释

文档注释只需在方法或类定义的上一行输入///即可自动生成注释模板。一般文档注释也只用在方法或类上。

// 单行注释

/*
多
行
注
释
*/

///<summary>
///文档注释
///</summary>
  • 快捷键:注释:Ctrl + K + C ,取消注释:Ctrl + K +U

1.5 占位符

占位符(placeholder)通常与字符串格式化一起使用,允许开发者在字符串中预留位置,以便在运行时插入具体的值。这些占位符通常被大括号{} 包围,并且内部可以包含数字索引或名称,用于指定要插入的值的位置或来源;

int x = 12345;  
double y = 123.456789;  
Console.WriteLine("整数: {0:N0}, 浮点数: {1:F2}", x, y);
// 格式化字符串: {0:N0} 表示整数 x 应该以千位分隔符的形式输出, {1:F2} 表示浮点数 y 应该输出两位小数

#运行结果:
整数: 12,345, 浮点数: 123.46
  • 命名占位符:除了数字索引占位符外,C#还支持命名占位符,提高代码可读性;
string name = "Alice";  
int age = 18;  
Console.WriteLine("我的名字是 {name},我 {age} 岁了。", name, age);

# 运行结果:
我的名字是 Alice,我 18 岁了。
  • 格式化字符串:占位符还可以与格式化字符串一起使用,以控制值的显示方式。

2. 数据类型


C#的五大数据类型:

  • 类(Class)
  • 结构体(Structures):如Int32、Int64、Double 等;
  • 枚举(Enumerations)
  • 接口(Interfaces)
  • 委托(Delegates)

在这里插入图片描述

上图中,蓝色字体表示其本身就是一个数据类型,黑色字体表示用语定义数据类型的关键字;

数据类型的作用:

  • 决定存储此类型变量所需的内存大小;
  • 此类型的值可表示的最大、最小值范围;
  • 此类型所包含的成员(如方法、属性、事件)
  • 此类型由何基类派生而来;
  • 程序运行时,此类型的变量会分配在内存的什么位置

2.1 值类型(Value types)

值类型数据可以直接分配给其一个值,不需要实例化;

即只需
int x =10;
而不需要
int x = new int();
x = 10;

比如int、char、float等数据类型,它们分别存储数字、字符、浮点数。当声明一个 int
类型的变量时,系统自动分配内存来存储该变量的值;

            byte buffer1 = 100; // 无符号字节
            sbyte buffer2 = -100; // 有符号字节
            ushort buffer3 = 1000;// 无符号短整型(16位)
            short buffer4 = -1000;// 有符号短整型(16位)
            string str = Convert.ToString(buffer4, 2); // 第二个参数是基数,2表示二进制
            Console.WriteLine(str);
            # 打印结果:1111110000011000

注: 小内存容纳大尺寸数据会丢失精度,发生错误;

2.1.1 结构体(Struct)

在 C# 中,结构体属于值类型数据结构。它可以存储各种数据类型的相关数据。这一点与C/C++原理相近。

2.1.1.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.1.1.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.1.2 枚举(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.2 引用类型(Reference types)

引用类型不包含存储在变量中的实际数据,但包含对变量的引用。即它们指向的是一个内存地址。内置的引用类型有:objectdynamicstring

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.2.4 列表 - List<T>

列表用于存储一系列对象的有序集合;其属于System.Collections.Generic命名空间;

using System;  
using System.Collections.Generic;  
  
class Program  
{  
    static void Main()  
    {  
        // 创建一个整数列表  
        List<int> list1 = new List<int>();  
          
        // 添加元素到列表  
        list1 .Add(1);  
        list1 .Add(2);  
        list1 .Add(3);  
          
        // 输出列表中的元素  
        foreach (int list_number in list1 )  
        {  
            Console.WriteLine(list_number);  
        }  
    }  
}
List<int> sortedNumbers = new List<int> { 5, 1, 9, 3, 7 };  // 定义的同时赋值
  • 列表的属性:
    在这里插入图片描述

  • 列表的方法:
    在这里插入图片描述

  • 列表与数组的区别:

    • 数组:数组在内存中是连续存储的,因此其索引速度非常快。数组的长度是固定的,在声明时必须指明长度。整个数组是以首地址开头的一块连续的内存单元;然而,数组存在一些不足,如在数组的两个数据间插入数据较为麻烦,且如果声明的数组长度过长或过短,可能会导致内存浪费或数据溢出错误;
    • 列表:列表是一个动态的数据结构,其长度不是固定的,可以根据需要动态增长或缩小;

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)

数组是一个存储相同类型元素的固定大小的有序的集合。

数组是由连续的内存位置组成的。最低的地址对应第一个元素,最高的地址对应最后一个元素。

  • 声明/初始化/赋值数组

数组是一个引用类型,需要使用 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; // 赋值一个数组变量到另一个数组
  • 访问数组元素:元素是通过带索引的数组名称来访问的。
double salary = balance[9];
  • 使用 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.1 多维数组

多维数组又称为矩形数组。一个二维数组,在本质上,是一个一维数组的列表。
在这里插入图片描述

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.6.2 交错数组

C# 中的交错数组其实就是元素为数组的数组,即交错数组中的每个元素都可以是维度和大小不同的数组;

int[][] jaggedArray = new int[3][]; // 声明一个交错数组
  • 初始化交错数组:
方法1int[][] jaggedArray = new int[3][]; // 定义一个交错数组
jaggedArray[0] = new int[5];        // 对数组的第一个元素初始化
jaggedArray[1] = new int[4];        // 对数组的第二个元素初始化
jaggedArray[2] = new int[2];        // 对数组的第三个元素初始化

方法2int[][] jaggedArray = new int[3][]; // 定义一个交错数组
jaggedArray[0] = new int[] {1, 2, 3, 4, 5};
jaggedArray[1] = new int[] {6, 7, 8, 9};
jaggedArray[2] = new int[] {10, 11};

方法3int[][] jaggedArray = new int[][]{
    new int[] {1, 2, 3, 4, 5},
    new int[] {6, 7, 8, 9},
    new int[] {10, 11}
};

  • 访问数组中的元素:
int a = jaggedArray[0][1]    // 变量 a 的值为:2
jaggedArray[2][1] = 0         // 将交错数组中第三个数组元素中的第二个元素赋值为 0
  • 交错数组和多维数组:
int[][,] jaggedArray = new int[3][,]
{
    new int[,] {
        {1, 1},
        {2, 3}
    },
    new int[,] {
        {5, 8},
        {13, 21},
        {34, 55}
    },
    new int[,] {
        {89, 144},
        {233, 377},
        {610, 987}
    }
};

运行结果:
int a = jaggedArray[1][1,1]     // 变量 a 的值为 21
int b = jaggedArray[2][0,0]     // 变量 b 的值为 89

2.6.3 Array 的属性

在这里插入图片描述

2.6.4 Array 的方法

在这里插入图片描述

2.6.5 params 关键字

params 关键字允许在方法定义中指定一个参数数组;在调用该方法时,可以传递任意数量的参数给这个特定的参数。这在设计灵活的 API 时非常有用,特别是当不知道调用者会传递多少个参数时。

params 关键字只能是方法的最后一个参数,并且该参数的类型必须是一维数组。

using System;  
  
class Program  
{  
    static void Main()  
    {  
        // 调用方法,传递不同数量的参数  
        PrintNumbers(1, 2, 3);  
        PrintNumbers(4, 5);  
        PrintNumbers(6);  
        PrintNumbers(); // 不传递任何参数也是可以的  
    }  
  
    // 使用 params 关键字定义方法,允许传递任意数量的 int 参数  
    static void PrintNumbers(params int[] numbers)  
    {  
        foreach (var number in numbers)  
        {  
            Console.WriteLine(number);  
        }  
    }  
}

2.7 字符(Char)与字符串(String)

2.7.1 字符

char 'a';// 字符类型只能有一个字符

注意字符与字符串是不同 大数据类型;

2.7.2 创建 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 20121010

2.7.3 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 数据类型转换

2.8.1 隐式类型转换

隐式类型转换是由 C# 以类型安全的方式执行的,转换的过程中不会导致数据丢失;

在这里插入图片描述

例程:
                int x = int.MaxValue;
                long y = x; // 不会造成数据丢失

2.8.2 显式类型转换

显式类型转换也叫强制类型转换,这种转换需要使用(type)value的形式或者预定义函数显式的完成,显式转换需要用户明确的指定要转换的类型,而且在转换的过程中可能会造成数据丢失;

在这里插入图片描述

例程:
                uint x = 65536;// 已知uint 的最大值为65535,此处二进制编码为0x1000
                ushort y = (ushort)x;// 强制类型转换,高16位舍弃,保留低16位,故此处输出为0

2.8.3 C# 内置的类型转换方法

在这里插入图片描述

  • 其他常用的数据类型转换方法:
  1. intstring
int a = 15;
string s1 = a.ToString(); // 方法1
string s2 = Convert.ToString(a); // 方法2



# 3. 变量
---
变量就是存放数据的地方,是内存中的一个区域;在 C# 中,每个变量都有一个指定的类型,此类型决定了该变量的内存大小和布局;


- **7种变量**- 静态变量
	- 实例变量
	- 数组元素
	- 值参数
	- 引用参数
	- 输出形参
	- 局部变量

```csharp
# 例程:
namespace ConsoleApp_CalssAndInstance
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student();
            stu1.age = 6;

            int[] arr1= new int[100]; // 数组
            arr1[0] = 1;
        }
    }
    class Student
    {
        public static int amount; // 静态成员变量
        public int age; // 字段,非静态成员变量
        public double Add(double a, double b) // a,b 是值参数变量
        { 
            return a + b;
        }
        public double Del(ref double a, out double b) // a 是引用参数变量,b 是输出参数变量
        {
            b = 1;
            return b;
        }
    }
}
  • 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,可为空值的数据类型
  • 变量声明的格式:有效的修饰符组合(可选)+类型+变量名+初始化器(可选)
public static int amount = 0; //public static + int + amount + = 0

2.9 变量作用域

  • 在函数内定义的局部变量只在其函数内作用。
  • 在类内函数外定义的变量可用在类内的函数中作用,但当该函数中存在同名变量时,则报错。

2.10 变量修饰符

  • 无修饰符:即变量类型无修饰符修饰。
  • out
  • ref

2.10.1 out 修饰符

out 修饰符用于方法参数,它指示该参数是一个输出参数。使用out 修饰符的参数必须在方法内部被赋值,并且在方法返回之前,必须确保该参数有一个明确的值。out 参数在传递到方法之前不需要初始化,因为在方法内部会重新为它们赋值。

使用 return 语句可以从函数中返回一个值,但是使用输出传递则out 可以从函数中一次性返回多个值。

// 声明带有out参数的方法
public void GetPersonInfo(string id, out string name, out int age)  
{  
    // 假设这是从数据库或其他数据源获取信息的代码  
    if (id == "123")  
    {  
        name = "John Doe";  
        age = 18;  
    }  
    else  
    {  
        name = null; // 或者可以抛出异常  
        age = 0;     // 或者使用其他默认值或错误码  
    }  
}
// 调用带有out参数的方法
string personName;  
int personAge;  
  
GetPersonInfo("123", out personName, out personAge);  
Console.WriteLine($"Name: {personName}, Age: {personAge}"); // 输出: Name: John Doe, Age: 18

2.10.2 ref 修饰符

ref 修饰符是一个关键字,用于按引用传递参数给方法。当使用ref 修饰符时,方法接收的是参数的引用(即内存地址),这意味着方法内部对参数的任何修改都会反映到原始变量上。

传入参数在被方法调用前必须赋有初值,并输入参数在被调用的方法内可被修改也可不修改

// 声明ref 参数
void Swap(ref int x, ref int y)  
{  
    int temp = x;  
    x = y;  
    y = temp;  
}
// 调用包含ref 参数的方法
int a = 5;  
int b = 10;  
Swap(ref a, ref b); // 调用Swap方法,传递a和b的引用  
Console.WriteLine($"a: {a}, b: {b}"); // 输出: a: 10, b: 5

// 在调用Swap方法时,我们使用了ref修饰符,并且传递了变量a和b的引用,而不是它们的值。因此,当Swap方法执行完毕后,a和b的值已经交换了。

2.11 var 变量

var 关键字用于隐式类型局部变量声明,使用 var 时,编译器会根据初始化表达式自动推断变量的类型。这种推断只在局部变量声明时有效,并且该变量在声明时必须立即初始化,而且一旦该变量的类型被确认后,该变量的类型则不能再被改变;
在这里插入图片描述

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)。

转义序列码有:

转义序列含义
| \ 字符
’ 字符
"" 字符
?? 字符
\aAlert 或 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#操作符官方页面:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/

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 操作符优先级

下表按运算符优先级从高到低列出各个运算符,在表达式中,较高优先级的运算符会优先被计算。
在这里插入图片描述
在这里插入图片描述

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);
}
  • foreach 循环: 使用 foreach 可以遍历数组或者集合对象中的每一个元素:
// foreach 语句语法例程
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 遍历的用法

  • 循环控制语句
控制语句描述
break 语句终止循环或 switch 语句,程序流继续执行紧接着循环或 switch 的下一条语句。即跳出当前循环语句
continue 语句跳出语句的本次循环
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Truffle7电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值