【学习笔记】C#基础 - 由C/C++衍生出来的面向对象的编程语言

一、程序结构

1、基本语法

csharp 复制代码
using System; // C#程序第一条语句都是 using System; 
// using 关键字(可多个):在程序中包含命名空间

namespace RectangleApplication // namespace 声明(可多个):包含一系列的类
{
    class Rectangle // class 声明(可多个):包含程序数据和方法声明
    {
        double width; // 变量声明:类的属性或数据成员,用于存储数据
        double length;

        public void Acceptdetails() // 函数声明:一系列执行指定任务的语句
        {
            width = 3.5;
            length = 4.5;
        }
        public double GetArea()
        {
            return width * length;
        }
        public void Display()
        {
            Console.WriteLine("Length:{0}", length);
            Console.WriteLine("Width: {0}", width);
            Console.WriteLine("Area: {0}", GetArea());
        }
    }
    class ExecuteRectangle // 实例化 Rectangle 的类
    {
        static void Main(string[] args) // Main 方法:定义类的动作(所有 C# 程序的入口点,程序执行从此开始)
        {
            Rectangle r = new Rectangle(); // 实例化 Rectangle
            r.Acceptdetails();
            r.Display();
            Console.ReadLine(); // 输出内容
        }
    }
}

2、类的命名

  1. 必须以 A-Z / _ / @ 开头,不能是数字,之后可以跟 A-Z0-9_@
  2. 不能包含任何空格或特殊符号,比如 ?-+!#%^&*()[]{}.;:"'/\
  3. 不能与关键字同名(除非添加 @ 前缀,@不作为标识符本身的一部分),不能与类库同名
  4. 必须区分大小写(PascalCase命名法)

3、关键字

  • 保留关键字

    abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in in(generic modifier) int interface internal is lock long namespace new null object operator out out(generic modifier) override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual void volatile while

  • 上下文关键字

    add alias ascending descending dynamic from get global group into join let orderby partial(type) partial(method) remove select set

二、数据类型

1、值(Value)类型

直接包含数据,当声明一个值类型时,系统分配内存来存储值

类型 描述 范围 默认值
bool 布尔值 True 或 False False
byte 8 位无符号整数 0 到 255 0
char 16 位 Unicode 字符 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
int 32 位有符号整数类型 -2,147,483,648 到 2,147,483,647 0
long 64 位有符号整数类型 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 0L
sbyte 8 位有符号整数类型 -128 到 127 0
short 16 位有符号整数类型 -32,768 到 32,767 0
uint 32 位无符号整数类型 0 到 4,294,967,295 0
ulong 64 位无符号整数类型 0 到 18,446,744,073,709,551,615 0
ushort 16 位无符号整数类型 0 到 65,535 0
csharp 复制代码
int i = 75;
float f = 53.005f;
double d = 2345.7652;
bool b = true;

Console.WriteLine("Size of int: {0}", sizeof(int)); // 获取任何机器上 int 类型的存储尺寸

2、引用(Reference)类型

不包含实际数据,仅包含对变量的引用(指向一个内存位置)

  • 对象类型object:通用类型系统中所有数据类型的终极基类,可以被分配任何其他数据类型的值(分配值之前需先进行类型转换)
csharp 复制代码
int i = 10;
object obj = i; // 装箱:将一个值类型转换为对象类型
int j = (int)obj; // 拆箱:将一个对象类型转换为值类型

// 拆箱时强转的值类型,应与装箱时的值类型一致

装箱 :在堆中自动创建一个对象实例,然后将该值复制到新对象内

拆箱 :检查是否是给定值类型的一个装箱值,然后将该值从实例复制到值类型变量中

  • 动态类型dynamic:存储任何类型的值,动态类型变量的类型检查是在运行时发生的
csharp 复制代码
/* 声明动态类型的语法 */
dynamic <variable_name> = value;

dynamic d = 20;
  • 字符串类型string:允许给变量分配任何字符串值(两种分配形式:引号和 @引号)
csharp 复制代码
/* 声明字符串类型的语法 */
string <variable_name> = value;

String str = "runoob.com";
string str = @"C:\Windows"; // 字符串前加 @ 可取消字符串中\的转义,将内容原样输出
string str = @"<script type=""text/javascript"">
    <!--
    -->
</script>"; // @字符串内容可换行书写,换行符及缩进空格都计算在字符串长度之内

3、指针(Pointer)类型

存储另一种类型的内存地址

csharp 复制代码
/* 声明指针类型的语法 */
type* identifier;

char* cptr;

4、无(Void)类型

对定义函数的参数类型、返回值、函数中指针类型进行声明

csharp 复制代码
public class Void Test{} // 无返回值
void* identifier; // 无类型指针:可以指向任何类型的数据

// void几乎只有"注释"和限制程序的作用,定义一个void变量没有意义

使用说明:

  1. 如果函数没有返回值,那么应声明为void类型
  2. 如果函数无参数,那么应声明其参数为void
  3. 小心使用void指针类型
  4. 如果函数的参数可以是任意类型指针,那么应声明其参数为void *
  5. void不能代表一个真实的变量

三、类型转换

  • 隐式类型转换:以安全方式进行转换,不会导致数据丢失
  • 显式类型转换:强制类型转换,需要强制转换运算符,并且会造成数据丢失
csharp 复制代码
double d = 5673.74;
int i;
i = (int)d; // 强制转换 double 为 int,输出 5673
方法 描述
ToBoolean 如果可能的话,把类型转换为布尔型
ToByte 把类型转换为字节类型
ToChar 如果可能的话,把类型转换为单个 Unicode 字符类型
ToDateTime 把类型(整数或字符串类型)转换为 日期-时间 结构
ToDecimal 把浮点型或整数类型转换为十进制类型
ToDouble 把类型转换为双精度浮点型
ToInt16 把类型转换为 16 位整数类型
ToInt32 把类型转换为 32 位整数类型
ToInt64 把类型转换为 64 位整数类型
ToSbyte 把类型转换为有符号字节类型
ToSingle 把类型转换为小浮点数类型
ToString 把类型转换为字符串类型
ToType 把类型转换为指定类型
ToUInt16 把类型转换为 16 位无符号整数类型
ToUInt32 把类型转换为 32 位无符号整数类型
ToUInt64 把类型转换为 64 位无符号整数类型
csharp 复制代码
int i = 75;
float f = 53.005f;
double d = 2345.7652;
bool b = true;

Console.WriteLine(i.ToString()); // 输出 "75"
Console.WriteLine(f.ToString()); // 输出 "53.005"
Console.WriteLine(d.ToString()); // 输出 "2345.7652"
Console.WriteLine(b.ToString()); // 输出 "True"

四、变量

变量只是一个供程序操作的存储区的名字;每个变量都有一个特定的类型,类型决定了变量的内存大小和布局;范围内的值可以存储在内存中,可以对变量进行一系列操作

类型 举例
整数类型 sbyte、byte、short、ushort、int、uint、long、ulong 和 char
浮点型 float 和 double
十进制类型 decimal
布尔类型 true 或 false 值,指定的值
空类型 可为空值的数据类型

1、变量定义

csharp 复制代码
/* 变量定义的语法 */
<data_type> <variable_list>;

// data_type:一个有效的数据类型
// variable_list:由一个或多个用逗号分隔的标识符名称组成

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

2、变量初始化

csharp 复制代码
/* 变量初始化的语法 */
variable_name = value;
<data_type> <variable_name> = value;

byte d = 3, f = 5;
double pi = 3.14159;
char x = 'x';

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

// ReadLine():接收来自用户的输入,并把它存储到一个变量中
// Convert.ToInt32():把用户输入的数据转换为 int 数据类型

3、两种表达式

  • lvalue 表达式:可以出现在赋值语句的左边或右边
  • rvalue 表达式:可以出现在赋值语句的右边,不能出现在赋值语句的左边

五、常量

常量是固定值,程序执行期间不会改变;常量可以是任何基本数据类型,可以被当作常规的变量,只是它们的值在定义后不能被修改

csharp 复制代码
/* 定义常量的语法 */
const <data_type> <constant_name> = value;

const int c1 = 5;

1、整数常量

csharp 复制代码
85 // 十进制
0213 // 八进制
0x4b // 十六进制
30 // 整型
30u // 无符号整型
30l // 长整型
30ul // 无符号长整型
前缀 含义
0x、0X 十六进制
0 八进制
(无) 十进制
后缀(可组合,不可重复) 含义
U、u unsigned(无符号)
L、l long(长)

2、浮点常量

csharp 复制代码
3.14159 // 小数形式:必须包含小数点或指数,或同时包含两者
314159E-5L // 指数形式:必须包含整数或小数,或同时包含两者,有符号的指数用e或E表示

3、字符常量

csharp 复制代码
'x' // 普通字符
'\t' // 转义序列
'\u02C0' // 通用字符
转义序列 含义
\\ \ 字符
\' ' 字符
\" " 字符
\? ? 字符
\a Alert 或 bell
\b 退格键(Backspace)
\f 换页符(Form feed)
\n 换行符(Newline)
\r 回车
\t 水平制表符 tab
\v 垂直制表符 tab
\ooo 一到三位的八进制数
\xhh . . . 一个或多个数字的十六进制数

4、字符串常量

csharp 复制代码
string a = "hello, world"; // hello, world
string b = @"hello, world"; // hello, world
string c = "hello \t world"; // hello     world
string d = @"hello \t world"; // hello \t world
string e = "Joe said \"Hello\" to me"; // Joe said "Hello" to me
string f = @"Joe said ""Hello"" to me"; // Joe said "Hello" to me
string g = "\\\\server\\share\\file.txt"; // \\server\share\file.txt
string h = @"\\server\share\file.txt"; // \\server\share\file.txt
string i = "one\r\ntwo\r\nthree";
string j = @"one
two
three";

六、运算符

1、算术运算符

运算符 描述 实例( A = 10, B = 20)
+ 把两个操作数相加 A + B → 30
- 从第一个操作数中减去第二个操作数 A - B → -10
* 把两个操作数相乘 A * B → 200
/ 分子除以分母 B / A → 2
% 取模运算符,整除后的余数 B % A → 0
++ 自增运算符,整数值增加 1 A++ → 11
-- 自减运算符,整数值减少 1 A-- → 9
csharp 复制代码
int a = 1;
int b;

b = a++; // 先将a赋值给b,再对a进行自增运算:a → 2, b → 1
b = ++a; // 先将a进行自增运算,再将a赋值给b:a → 2, b → 2
b = a--; // 先将a赋值给b,再对a进行自减运算:a → 0, b → 1
b = --a; // 先将a进行自减运算,再将a赋值给b:a → 0, b → 0

2、关系运算符

运算符 描述 实例( A = 10, B = 20)
== 检查两个操作数的值是否相等,如果相等则条件为真 A == B → false
!= 检查两个操作数的值是否相等,如果不相等则条件为真 A != B → true
> 检查左操作数的值是否大于右操作数的值,如果是则条件为真 A > B → false
< 检查左操作数的值是否小于右操作数的值,如果是则条件为真 A < B → true
>= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真 A >= B → false
<= 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真 A <= B → true

3、逻辑运算符

运算符 描述 实例( A = true, B = false)
&& 逻辑与运算符:如果两个操作数都非零,则条件为真 A && B → false
|| 逻辑或运算符:如果两个操作数中有任意一个非零,则条件为真。 A || B → true
! 逻辑非运算符:用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假 !(A && B) → true

4、位运算符

将条件值换算为二进制数后进行位运算,再将结果换算回去得出最终结果

运算符 描述 实例( A = 60, B = 13)
& 如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中 A & B → 12(0000 1100)
| 如果存在于任一操作数中,二进制 OR 运算符复制一位到结果中 A | B → 61(0011 1101)
^ 如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制异或运算符复制一位到结果中 A ^ B → 49(0011 0001)
~ 按位取反运算符是一元运算符,具有"翻转"位效果,即0变成1,1变成0,包括符号位 ~A → -61(1100 0011)
<< 二进制左移运算符。左操作数的值向左移动右操作数指定的位数 A << 2 → 240(1111 0000)
>> 二进制右移运算符。左操作数的值向右移动右操作数指定的位数 A >> 2 → 15(0000 1111)

5、赋值运算符

运算符 描述 实例
= 简单的赋值运算符,把右边操作数的值赋给左边操作数 C = A + B 将把 A + B 的值赋给 C
+= 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 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
|= 按位或且赋值运算符 C |= 2 等同于 C = C | 2

6、其他运算符

运算符 描述 实例
sizeof() 返回数据类型的大小 sizeof(int)
typeof() 返回 class 的类型 typeof(StreamReader)
& 返回变量的地址 &a
* 变量的指针 *a
? : 条件表达式 c ? a : b
is 判断对象是否为某一类型 If(Ford is Car)
as 强制转换,即使转换失败也不会抛出异常 Object obj = new StringReader("Hello"); StringReader r = obj as StringReader;

运算符优先级:

() [] -> . ++ - -

    • ! ~ ++ - - (type)* & sizeof()

* / %

<< >>

< <= > >=

== !=

&

^

|

&&

||

?:

= += -= *= /= %=>>= <<= &= ^= |=

,

七、判断

  • if 语句
csharp 复制代码
if (boolean_expression)
{
   /* 如果布尔表达式为真将执行的语句 */
}
  • if...else 语句
csharp 复制代码
if (boolean_expression)
{
   /* 如果布尔表达式为真将执行的语句 */
}
else
{
  /* 如果布尔表达式为假将执行的语句 */
}

// 条件运算符可替代 if...else 语句:
Exp1 ? Exp2 : Exp3;

// if...else if...else 语句:
if (boolean_expression 1)
{
   /* 当布尔表达式 1 为真时执行 */
}
else if (boolean_expression 2)
{
   /* 当布尔表达式 2 为真时执行 */
}
else if (boolean_expression 3)
{
   /* 当布尔表达式 3 为真时执行 */
}
else 
{
   /* 当上面条件都不为真时执行 */
}

// 另一种写法:
if (a == true)
    x = 1; // 若不书写花括号{},则默认只第一条语句由if执行
    y = 2; // 之后的语句则在if语句之后执行
    z = 3;
  • 嵌套 if 语句
csharp 复制代码
if (boolean_expression 1)
{
   /* 当布尔表达式 1 为真时执行 */
   if (boolean_expression 2)
   {
      /* 当布尔表达式 2 为真时执行 */
   }
}
  • switch 语句
csharp 复制代码
switch (expression){
    case constant-expression  :
       statement(s);
       break; 
    case constant-expression  :
       statement(s);
       break; 
  
    /* 您可以有任意数量的 case 语句 */
    default : /* 可选的 */
       statement(s);
       break; 
}

switch语句规则:

  1. expression 必须是一个整型或枚举类型,或者是一个 class 类型,其中 class 有一个单一的转换函数将其转换为整型或枚举类型。
  2. 在一个 switch 中可以有任意数量的 case 语句,每个 case 后跟一个要比较的值和一个冒号。
  3. case 的 constant-expression 必须与 switch 中的变量具有相同的数据类型,且必须是一个常量。
  4. 当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到 break 语句时switch 终止,控制流将跳转到 switch 语句后的下一行。
  5. 如果 case 语句中有处理语句,则必须包含 break 或其他跳转语句;如果 case 语句为空,则可以不包含 break,控制流将会继续后续的 case,直到遇到 break 为止。
  6. 一个 switch 语句结尾可以有一个可选的 default case,用于在上面所有 case 都不为真时执行一个任务,default case 中的 break 语句不是必需的。
  7. C# 不支持从一个 case 标签显式贯穿到另一个 case 标签,如需要,可以使用 goto 一个 switch-case 或 goto default。
  • 嵌套 switch 语句
csharp 复制代码
switch (ch1)
{
   case 'A':
      printf("这个 A 是外部 switch 的一部分" );
      switch (ch2)
      {
         case 'A':
            printf("这个 A 是内部 switch 的一部分" );
            break;
         case 'B': /* 内部 B case 代码 */
      }
      break;
   case 'B': /* 外部 B case 代码 */
}

八、循环

1、循环类型

  • while 循环
csharp 复制代码
while (condition) // condition 可以是任意的表达式,当为任意非零值时都为真
{
   statement(s); // 可以是一个单独的语句,也可以是几个语句组成的代码块
}
  • for/foreach 循环
csharp 复制代码
/* for 循环语法 */
for (init; condition; increment)
{
   statement(s);
}

/* foreach 循环语法 */
foreach (type objName in collection/Array)
{
   statement(s);
}

int[] fibarray = new int[] {0, 1, 1, 2, 3, 5, 8, 13};
foreach (int element in fibarray)
{
    System.Console.WriteLine(element);
}

for循环控制流:

  1. init 会首先被执行,且只会执行一次;允许声明并初始化任何循环控制变量,也可以只写一个分号。
  2. 判断 condition,如果为真则执行循环主体,如果为假则直接跳到紧接着 for 循环的下一条语句。
  3. 执行完 for 循环主体后,控制流会跳回 increment 语句,允许更新循环控制变量,也可以留空。
  4. 重复判断 condition,直到条件变为假时,循环终止。
  • do...while 循环
csharp 复制代码
do
{
   statement(s);
} while (condition);

do...while循环控制流:

  1. 条件表达式出现在循环的尾部,所以循环中的 statement(s) 会在条件被测试之前至少执行一次。
  2. 如果 condition 为真,控制流会跳转回上面的 do,重新执行循环中的 statement(s)。
  3. 重复判断 condition,直到条件变为假时,循环终止。
  • 嵌套循环
csharp 复制代码
/* 嵌套 for 循环语法 */
for (init; condition; increment)
{
   for (init; condition; increment)
   {
      statement(s);
   }
   statement(s);
}

/* 嵌套 while 循环语法 */
while (condition)
{
   while (condition)
   {
      statement(s);
   }
   statement(s);
}

/* 嵌套 do...while 循环语法 */
do
{
   statement(s);
   do
   {
      statement(s);
   } while (condition);

} while (condition);

2、循环控制语句

用于更改执行的正常序列,当执行离开一个范围时,所有在该范围中创建的自动对象都会被销毁

  • break 语句
循环 作用
switch break 用于终止一个 case
其他 break 会终止整个循环,且程序流将继续执行紧接着循环的下一条语句
csharp 复制代码
int a = 10;
while (a < 20)
{
    a++;
    if (a > 15)
    {
        break; // a>15时终止while循环
    }
}
  • continue 语句
循环 作用
for continue 语句会导致执行条件测试和循环增量部分
while、do...while continue 语句会导致程序控制回到条件测试上
其他 continue 会跳过当前循环中的代码,强迫开始下一次循环
csharp 复制代码
int a = 10;
do
{
    if (a == 15)
    {
        a = a + 1;
        continue; // a==15时跳过这次迭代,继续循环
    }
    a++;
} while (a < 20);

3、无限循环

如果条件永远不为假,则循环将变成无限循环

csharp 复制代码
for (; ; ) // 当条件表达式不存在时,它被假设为真
{
    Console.WriteLine("陷入死循环啦!");
}

九、封装

把一个或多个项目封闭在一个物理的或者逻辑的包中,通过访问修饰符设置使用者的访问权限,防止对实现细节的访问

访问修饰符 访问权限
public 所有对象都可以访问
protected internal 访问限于当前程序集或派生自包含类的类型
internal 同一程序集内的对象可以访问
protected 只有该类对象及其子类对象可以访问
private 对象本身在对象内部可以访问

1、Public 访问修饰符

允许一个类将其成员变量和成员函数暴露给所有函数和对象,当前程序集(项目)及外部程序集(项目)都可以访问

csharp 复制代码
namespace RectangleApplication
{
    class Rectangle
    {
        public double length;
        public double width;
        public double GetArea()
        {
            return length * width;
        }
        public void Display()
        {
            Console.WriteLine("长度: {0}", length);
            Console.WriteLine("宽度: {0}", width);
            Console.WriteLine("面积: {0}", GetArea());
        }
        /* 成员变量及函数被声明为 public,故可被所有函数及类的实例访问 */
    }

    class ExecuteRectangle
    {
        static void Main(string[] args)
        {
            Rectangle r = new Rectangle();
            r.length = 4.5;
            r.width = 3.5;
            r.Display();
            Console.ReadLine();
        }
    }
}

2、Protected Internal 访问修饰符

允许在本类、派生类或者包含该类的程序集中访问,用于实现继承

3、Internal 访问修饰符

允许一个类将其成员变量和成员函数暴露给当前程序集中的其他函数和对象,外部程序集(项目)不可访问

csharp 复制代码
namespace RectangleApplication
{
    class Rectangle
    {
        internal double length;
        internal double width;
        /* 成员变量被声明为 internal,故可被当前程序集的函数访问,不可被外部访问 */
        
        double GetArea() // 成员函数声明时不带有任何访问修饰符,默认为 private
        {
            return length * width;
        }
        public void Display()
        {
            Console.WriteLine("长度: {0}", length);
            Console.WriteLine("宽度: {0}", width);
            Console.WriteLine("面积: {0}", GetArea());
        }
    }
    
    class ExecuteRectangle
    {
        static void Main(string[] args)
        {
            Rectangle r = new Rectangle();
            r.length = 4.5;
            r.width = 3.5;
            r.Display();
            Console.ReadLine();
        }
    }
}

4、Protected 访问修饰符

允许子类访问它的基类的成员变量和成员函数,有助于实现继承

5、Private 访问修饰符

允许一个类将其成员变量和成员函数对其他的函数和对象进行隐藏,只有当前类的成员函数可以访问(类的实例不能访问)

csharp 复制代码
namespace RectangleApplication
{
    class Rectangle
    {
        private double length;
        private double width;
        /* 成员变量被声明为 private,故可被当前类的成员函数访问,不可被类外访问 */
        
        public void Acceptdetails()
        {
            Console.WriteLine("请输入长度:");
            length = Convert.ToDouble(Console.ReadLine());
            Console.WriteLine("请输入宽度:");
            width = Convert.ToDouble(Console.ReadLine());
        }
        public double GetArea()
        {
            return length * width;
        }
        public void Display()
        {
            Console.WriteLine("长度: {0}", length);
            Console.WriteLine("宽度: {0}", width);
            Console.WriteLine("面积: {0}", GetArea());
        }
    }
    
    class ExecuteRectangle
    {
        static void Main(string[] args)
        {
            Rectangle r = new Rectangle();
            r.Acceptdetails();
            r.Display();
            Console.ReadLine();
        }
    }
}

注:如果类成员没有指定访问修饰符,则默认为 private

十、方法

1、定义及调用方法

csharp 复制代码
/* 定义方法的语法 */
<Access Specifier> <Return Type> <Method Name>(Parameter List)
{
   Method Body
}

// Access Specifier:访问修饰符,声明变量或方法对于另一个类的可见性
// Return type:方法返回的值的数据类型,若无返回值则类型为 void
// Method name:方法名称,标识符唯一,且大小写敏感
// Parameter list:参数列表,用来传递和接收方法的数据
// Method body:方法主体,包含了完成任务所需的指令集

class NumberManipul
{
    /* 定义方法:访问修饰符 public,返回类型 int,方法名 FindMax,以及参数和主体 */
    public int FindMax(int num1, int num2)
    {
        int result;
        /* 若if内只执行一条语句,可以省略花括号{} */
        if (num1 > num2)
            result = num1;
        else
            result = num2;
            
        return result;
    }
    
    static void Main(string[] args)
    {
        int a = 100;
        int b = 200;
        int ret;
        NumberManipul n = new NumberManipul(); // 实例化 NumberManipul 类
        ret = n.FindMax(a, b); // 调用 FindMax 方法
        Console.WriteLine("最大值是: {0}", ret );
        Console.ReadLine();
    }
}

2、递归函数

一个方法可以自我调用,这就是所谓的递归

csharp 复制代码
class NumberManipulator
{
    public int factorial(int num)
    {
        int result;
        if (num == 1)
        {
            return 1;
        }
        else
        {
            result = factorial(num - 1) * num; // 调用自身并迭代参数以实现递归
            return result;
        }
    }
    
    static void Main(string[] args)
    {
        NumberManipulator n = new NumberManipulator();
        Console.WriteLine("6 的阶乘是: {0}", n.factorial(6));
        Console.WriteLine("7 的阶乘是: {0}", n.factorial(7));
        Console.WriteLine("8 的阶乘是: {0}", n.factorial(8));
        Console.ReadLine();
    }
}

3、参数传递

  • 按值传递参数(默认方式)

当调用一个方法时,会为每个值参数创建一个新的存储位置;实际参数的值会复制给形参,实参和形参使用的是两个不同内存中的值,所以,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全

csharp 复制代码
class NumberManipulator
{
    public void swap(int x, int y)
    {
        int temp;
        temp = x; // 保存 x 的值
        x = y; // 把 y 赋值给 x
        y = temp; // 把 temp 赋值给 y
    }
    
    static void Main(string[] args)
    {
        NumberManipulator n = new NumberManipulator();
        int a = 100;
        int b = 200;
        Console.WriteLine("在交换之前,a 的值: {0}", a);
        Console.WriteLine("在交换之前,b 的值: {0}", b);
        n.swap(a, b); // 调用函数来交换值
        Console.WriteLine("在交换之后,a 的值: {0}", a);
        Console.WriteLine("在交换之后,b 的值: {0}", b);
        Console.ReadLine();
    }
}

/* 结果表明,即使在函数内改变了值,值也没有发生任何的变化 */
  • 按引用传递参数

引用参数是一个对变量的内存位置的引用,它不会创建新的存储位置,而是与实际参数具有相同的内存位置,使用 ref 关键字声明引用参数

csharp 复制代码
class NumberManipulator
{
    public void swap(ref int x, ref int y)
    {
        int temp;
        temp = x; // 保存 x 的值
        x = y; // 把 y 赋值给 x
        y = temp; // 把 temp 赋值给 y
    }
    
    static void Main(string[] args)
    {
        NumberManipulator n = new NumberManipulator();
        /* ref参数需在传递前初始化变量 */
        int a = 100;
        int b = 200;
        Console.WriteLine("在交换之前,a 的值: {0}", a);
        Console.WriteLine("在交换之前,b 的值: {0}", b);
        n.swap(ref a, ref b); // 调用函数来交换值
        Console.WriteLine("在交换之后,a 的值: {0}", a);
        Console.WriteLine("在交换之后,b 的值: {0}", b);
        Console.ReadLine();
    }
}

/* 结果表明,swap 函数内的值改变了,且这个改变可以在 Main 函数中反映出来 */
  • 按输出传递参数

输出参数也是一个对变量的内存位置的引用,它会把方法输出的数据赋给自己,可从函数中返回两个值,使用 out 关键字声明输出参数;提供给输出参数的变量不需要赋值,而当需要从一个未指定参数初始值的方法中返回值时,输出参数特别有用

csharp 复制代码
class NumberManipulator
{
    public void getValues(out int x, out int y)
    {
        /* out参数需在函数内部初始化变量 */
        Console.WriteLine("请输入第一个值:");
        x = Convert.ToInt32(Console.ReadLine());
        Console.WriteLine("请输入第二个值:");
        y = Convert.ToInt32(Console.ReadLine());
    }
   
    static void Main(string[] args)
    {
        NumberManipulator n = new NumberManipulator();
        int a, b;
        n.getValues(out a, out b); // 调用函数来获取值
        Console.WriteLine("在方法调用之后,a 的值: {0}", a);
        Console.WriteLine("在方法调用之后,b 的值: {0}", b);
        Console.ReadLine();
    }
}

/* 获取的结果完全取决于用户输入 */

十一、可空类型(Nullable)

1、Nullable 类型定义?

表示其基础值类型正常范围内的值,再加上一个 null 值,用于对 int, double, bool 等数据类型进行 null 的赋值

csharp 复制代码
/* 声明一个 nullable 类型的语法 */
<data_type>? <variable_name> = null;

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、Null 合并运算符??

用于定义可空类型和引用类型的默认值,为类型转换定义了一个预设值,以防可空类型的值为 Null;Null 合并运算符把操作数类型隐式转换为另一个可空(或不可空)的值类型的操作数的类型,如果第一个操作数的值为 null,则返回第二个操作数的值,否则返回第一个操作数的值

csharp 复制代码
class NullablesAtShow
{
    static void Main(string[] args)
    {
        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 的值
        Console.WriteLine("num3 的值: {0}", num3);
        Console.ReadLine();
    }
}

十二、数组(Array)

1、数组基础

csharp 复制代码
/* 声明一个数组的语法 */
datatype[] arrayName;

// datatype:指定被存储在数组中的元素的类型
// []:指定数组的秩(维度),秩指定数组的大小
// arrayName:指定数组的名称

double[] balance; // 声明数组
double[] balance = {2340.0, 4523.69, 3421.0}; // 声明并赋值给数组

double[] balance = new double[10]; // 初始化一个长度为10的数组(元素为默认值)
balance[0] = 4500.0; // 通过索引号赋值给单个元素

int[] marks = new int[5]  {99,  98, 92, 97, 95}; // 创建并初始化一个数组
int[] marks = new int[]  {99,  98, 92, 97, 95}; // 省略数组长度的写法
int[] score = marks; // 赋值一个数组变量到另一个数组变量中

2、数组细节

  • 多维数组
csharp 复制代码
string [,] names; // 声明一个 string 变量的二维数组
int [,,] m; // 声明一个 int 变量的三维数组

(未完待续)

相关推荐
xiaobai12 3几秒前
二叉树的遍历【C++】
开发语言·c++·算法
DieSnowK7 分钟前
[项目][WebServer][Makefile & Shell]详细讲解
开发语言·c++·http·makefile·shell·项目·webserver
ling1s29 分钟前
C#基础(13)结构体
前端·c#
.Net Core 爱好者1 小时前
Redis实践之缓存:设置缓存过期策略
java·redis·缓存·c#·.net
dc爱傲雪和技术1 小时前
在 VS Code 中调试 C++ 项目
开发语言·c++
如意.7591 小时前
【C++】——多态详解
开发语言·c++
云草桑1 小时前
逆向工程 反编译 C# net core
前端·c#·反编译·逆向工程
我爱吃福鼎肉片1 小时前
【C++】——list
c++·vector·list
溪午闻璐2 小时前
C++ 文件操作
开发语言·c++
LaoWaiHang2 小时前
C语言从头学61——学习头文件signal.h
c语言