番禺网站建设培训学校,做网站一月能赚50万吗,怎么开发游戏软件赚钱,做网站泊头方法
方法定义
方法可以将一组复杂的代码进行打包。 声明方法的语法是返回类型 方法名 括号 方法体。
void Hello1()
{for (int i 0; i 10; i){Console.WriteLine(Hello);}
}调用方法
方法的主要特征就是他的括号。 调用方法的语法是方法名括号。
He…方法
方法定义
方法可以将一组复杂的代码进行打包。 声明方法的语法是返回类型 方法名 括号 方法体。
void Hello1()
{for (int i 0; i 10; i){Console.WriteLine(Hello);}
}调用方法
方法的主要特征就是他的括号。 调用方法的语法是方法名括号。
Hello1();当调用方法时就会执行方法体内的代码。 在多个地方需要使用同一组复杂代码时使用方法打包会减少代码量。 相较于直接复制这些代码打包成方法更方便后续的修改。 只需要修改方法体内部的代码所有调用方法的地方执行的代码都会被修改。
作用域
方法体的声明也有一个大括号所以这也是一个作用域。 在大括号里声明的东西不能在大括号外访问。 如果Int2定义在一个if块中也是同样的效果。
void Int1()
{int i1 10;//这个变量只能在Int1内部访问void Int2()//这个方法只能在Int1内部访问{int i2 i1;//允许访问}
}
Int2();//无法访问超出作用域
i1 5;//无法访问超出作用域返回值
void表示方法不会返回值。它可以改成一个具体类型方法在调用完毕后就会返回这个类型的值。 必须在方法内部使用return指明要返回的值。
string String1()
{var i Random.Shared.Next(100);return ${i * i};
}在调用方法的时候这个方法就可以被认为是一个值可以用来给变量赋值或是参与到表达式计算中。
string s1 随机数是 String1();流程控制
return同时有结束方法的作用。在void方法中不能在后面跟随值来返回但可以单独使用来结束方法。
void Random1()
{while (true){int i Random.Shared.Next(100);Console.WriteLine(随机数是 i);if (i 5){return;}}
}但是对于有返回值的方法在必须使用return来结束方法如果方法能结束即没有死循环。 如果使用了流程控制语句需要注意你认为必定会执行的流程编译器可能不会这么认为。
int Int3()
{int i 0;while (i 100){i;return i;}return i;//尽管你认为这个方法必然会从上面的循环中返回。//但对编译器来说那个循环可能完全不会执行。//必须要在方法结束的地方另外写一个返回语句。
}方法调用可以单独作为语句一行放置。 如果它有返回值而你不需要用到他的值不需要做额外的处理当作无返回值的方法就行。 引用返回值
引用变量也是有效的返回值类型。
ref int Int4()
{int[] arr new int[1];return ref arr[0];
}返回引用变量的方法可以取引用也可以直接取值。
ref int i2 ref Int4();
int i3 Int4();参数
声明方法的时候可以在方法的括号里声明变量。 他们不需要赋值初始值。多个参数用逗号隔开并且要写明类型即便他们类型相同。
int Max1(int i1, int i2, int i3)
{if (i1 i2){return i1 i3 ? i1 : i3;}else{return i2 i3 ? i2 : i3;}
}在调用方法的时候需要在括号里填入对应的值。 使用逗号隔开顺序和类型都对应上。 这些值将作为初始值赋值给这些参数。
int i4 Max1(9, 6, 8);
Console.WriteLine(i4);//9捕获与隔离
方法里可以直接使用外部的变量。这称为捕获变量。 任何对捕获变量的修改都会直接作用到它身上。
int i5 40;
Hello2();
Console.WriteLine(i5);//6
void Hello2()
{i5 6;
}而方法的参数可以声明和作用域外部同名的参数。 这样在方法内对它的修改只会改动到参数不会影响到外部同名的变量。
int i6 40;
Hello3(0);
Console.WriteLine(i6);//40
void Hello3(int i5)
{i5 6;
}可选参数
参数可以赋值初始值但必须是常量或者default。 如果一个参数有初始值那么他们之后的所有变量都要有初始值。
void Random2(int max 100, int critical 20)
{if (Random.Shared.Next(max) critical){Console.WriteLine(暴击);}else{Console.WriteLine(没有暴击);}
}有初始值的参数在调用的时候可以不必填入初始值 也可以正常填入值来覆盖预定义的初始值。
Random2();
Random2(40);
Random2(1000, 800);不定长参数
如果参数的最后一个变量是数组那么可以使用params修饰。 params修饰的数组不能有默认值。所以不定长参数和可选参数不能同时使用
int Min1(params int[] arr)
{if (arr.Length 0)return 0;int min arr[0];for (int i 1; i arr.Length; i){if (min arr[i])min arr[i];}return min;
}在调用的时候可以直接传入一个数组 也可以以散装的形式填入。
Min1();
Min1(1);
Min1(6,9);
Min1(8,4,2);命名参数
默认情况下调用方法时需要按照参数在定义时的顺序来填入。 但如果指明这个值是给哪个参数的那么可以乱序。
Hello4(b: 8, a: 9, d: 10);//输出9,8,6,10void Hello4(int a, int b, int c 6, int d 40)
{Console.WriteLine(a);Console.WriteLine(b);Console.WriteLine(c);Console.WriteLine(d);
}这种方式可以在有多个可选参数时保持前面可选参数的默认值。
引用参数
参数可以设置为引用变量在前面加上ref。
void Hello5(ref int i)
{i * 2;
}就像给引用变量赋值时一样在调用方法时也需要加上ref来把变量取指针。
int i7 10;
Hello5(ref i7);
Console.WriteLine(i7);//20in
引用参数还有两种形式in表示只读。 虽然是引用方式获得的变量但不允许在方法中对他进行修改。 这样做的意义是为了防止复制太大的值类型。指针无论如何都只有4字节到8字节。
out
out参数在方法中不会得到变量的初始值。 必须在脱离方法前对他进行赋值。
对已有的变量修改效果和ref一样。但out参数还可以在调用方法时当场声明一个变量。
if (int.TryParse(123, out var input))
{Console.WriteLine(input * input);
}
else
{Console.WriteLine(输入不合法);
}元组
元组类型
方法的返回类型是固定的不能在某种条件下返回int在另一种条件下返回bool。 但是可以把这两个数据打包一起返回。这需要一种包含多种数据却是单独的类型。
除了数组可以打包多个同种类型数据外元组可以打包固定数量和确定类型的数据。 元组的声明为把多个类型以逗号分隔然后把他们加上小括号。
(string, int) Hello6((string, int) stu)
{return stu;
}打包和解构
将同样数量顺序类型的一堆值以逗号分隔打上括号就能打包成一个元组类型。
(string, int) stu1 (小明, 18);//声明元组并为元组赋值
(string name1, int age1) stu1;//析构元组声明两个变量接收他们
Console.WriteLine(name1);
Console.WriteLine(age1);在元组类型后加上变量名是一个元组类型的声明。 如果不加变量名那么就是元组的解构。 元组会把打包的数据依次赋值给这些变量。
解构的时候可以声明变量也可以对已有的变量覆盖值。 在解构时可以使用下划线_来舍弃一些值。 直接使用打包和解构可以在单语句中交换变量的值。
int id2;
(_, int age2, id2) (小明, 18, 1006);//析构元组舍弃一个值声明一个变量覆盖一个已有变量
(age2, id2) (id2, age2);//交换age2和id2的值元素命名
无命名
元组中的元素可以单独访问和修改。 任何情况下元组中的元素都可以使用Item1Item2Item3这种形式访问从1开始计数
(string, int) stu3 (小明, 18);
string name3 stu3.Item1;
stu3.Item2 66;类型命名
在声明元组类型时可以为元素直接命名。 命名后依然可以使用Item1Item2Item3进行访问并且不可指定这些值作为名字。
(string name, int age) stu4 (小明, 18);
string name4 stu4.name;
stu4.Item2 66;值命名
如果使用var来声明元组可以在声明值的时候为值指定元素名。
var stu5 (name: 小明, age: 18);
var name5 stu5.name;
stu5.age 88;推断命名
如果你使用var来声明元组并且没有给值指定名字但你使用的是变量不是表达式常量方法。 那么会使用变量名来作为元素名。
string s1 hello;
var slength (s1, s1.Length);
var length slength.Length;
slength.s1 world;可空值类型
在设置值类型的参数时我们可能需要一些更特殊的值而不是default。 例如将一个int的默认值设置为0我们无法分辨到底是没有填写保持默认值 还是真的需要以0为参数来做处理。
我们可以使用可空值类型在值类型后加上?他将可以接收null值。
int Random3(int max 100, int? min null)
{if (min null)return Random.Shared.Next(max);elsereturn Random.Shared.Next(min.Value, max);
}可空值类型是他原本类型的包装类型。 他有两个属性HasValue和Value。 HasValue是判断这个值有没有值效果和null一样。 如果有值使用Value访问他的值。但是如果是null这个访问会报错。
提升运算符
可空值类型继承了基础类型的运算符这一特性是配合编译器联合工作的结果我们无法复刻。 可空值类型在使用基础类型的运算符时遵循以下规则
如果没有null参与按基础类型的方式执行。但返回值为可空值类型。当使用关系运算符时 当双方为null且使用运算时返回true当仅一方为null且使用!运算时返回true否则返回false 其他二元运算符返回null
对于bool?类型是例外他可以在一方为null的情况下返回非null值。 他不能使用逻辑运算符他的位运算符逻辑如下。
a | b等效a true || b true ? truea false b false ? false: nulla b等效a true b true ? truea false || b false ? false: null空传播
在你访问一个值的内容时可以在.或[前面加个?表示空传播。 只要左侧的值是null那么会阻止之后的所有内容访问不会异常并且返回null
string[]? arr1 null;
string? s2 arr1?[0];//不会阻止索引越界
int? i8 s2?.Length;
var i9 arr1?[0].Length;//只要arr1是null后面的.Length也不会执行如果是值类型那么空传播就会返回可空值类型。 对可空值类型使用时会直接访问到Value的内容。
int? i10 2;
var s3 i10.Value.ToString();
var s4 i10?.ToString();空容忍
对引用类型加?不会发生什么事因为他们本来就可以接收null值。 只不过如果你不加?编译器会认为你不希望这个变量接收一个null值 在赋值的时候他会分析这些值如果可能是null就会向你发出警告。 如果你不希望提示这个警告可以在值的右侧加上!表示我不在乎他是不是null。
int? i11 10;
string s5 i11?.ToString()!;合并运算
使用x ?? y运算符来简写x null ? x : y 同样有他的赋值复合运算。
string s6 null;
int i11 s6?.Length ?? -1;
s6 ?? hello;如果合并运算表达式右侧的值不为null则这个表达式的值会被认为是不为null的类型。 即对一个可空值类型使用合并运算并给默认值会转为基础类型。
引用类型除了string类型外他们只能接收null作为可选参数默认值。 使用合并运算以方便的为可选引用类型参数在方法内指定默认值。
int Random4(Random? random null)
{random ?? Random.Shared;return random.Next(100);
}