C#
基础
程序 = 数据结构 + 算法
依赖关系
1.类之间的耦合关系即为依赖
2.优秀的程序员需要做到“高内聚,低耦合”。
注释:将同功能的函数聚集到合适的类中,同类型的类聚集到合适的命名空间中。降低类与类的依赖。
3.UML(通用建模语言)类图
类是现实世界中事务抽象后得到的。
类与对象的关系
1.对象的也叫实例,是经过实例化后获得内存中的实体
2.按照类创建对象,这个就是实例化。
3.使用new关键词创建类的实例
4.类的引用
new Program();//实例化 Program program = new Program();//引用实例
类的三大成员
属性(Property)
存储数据,组合起来表示类或者对象的状态
方法(Method)
表示类能做什么。
事件(Event)
类或者对象通知其他类的一种机制,为C#所特有
C#类型系统
类(Class)
结构体(Structures)
枚举(Enumerations)
接口(Interface)
委托(Delegates)
C#将int这类数据类型封装成了结构体
class 申明类
struct 申明结构体
meun 申明枚举
关键字
保留关键字 | ||||||
---|---|---|---|---|---|---|
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 |
标识符
标识符是用来识别类、变量、函数或任何其它用户定义的项目。在 C# 中,类的命名必须遵循如下基本规则:
- 标识符必须以字母、下划线或 @ 开头,后面可以跟一系列的字母、数字( 0 - 9 )、下划线( _ )、@。
- 标识符中的第一个字符不能是数字。
- 标识符必须不包含任何嵌入的空格或符号,比如 ? - +! # % ^ & * ( ) [ ] { } . ; : " ’ / \。
- 标识符不能是 C# 关键字。除非它们有一个 @ 前缀。 例如,@if 是有效的标识符,但 if 不是,因为 if 是关键字。
- 标识符必须区分大小写。大写字母和小写字母被认为是不同的字母。
- 不能与C#的类库名称相同。
來自 https://www.runoob.com/csharp/csharp-basic-syntax.html
var
var 申明隐式变量
var v = "String";//隐式申明,编译器自动推断变量的数据类型,一旦确定则不能再更改。
Console.WriteLine(v.GetType().Name);
操作符
运算符就是操作符的别称
操作符是和数据类型挂钩的。
//new 操作符创建类的实例,并且调用其构造方法。
//如果new操作符左侧有赋值操作符的话,将会将创建的实例的内存地址交给左侧
//new 操作符还可以调用初始化器
Form form = new Form(){Text = "this is title"};
form.ShowDialog();
//new 操作符可以申明匿名对象
//var 变量名 = new {属性列表};
//new 为匿名对象创建实例,var 为隐式类型变量引用变量
var person = new { name = "张三", age = 18 };
Console.WriteLine(person.name);
Console.WriteLine(person.age);
Console.WriteLine(person.GetType().Name);
internal class Father
{
public void Report()
{
Console.WriteLine("this is Father!");
}
}
class Son:Father {
//new 关键字可以隐藏父类方法
new public void Report()
{
Console.WriteLine("this is Son!");
}
}
uint i = uint.MaxValue;
Console.WriteLine(i);
string str = Convert.ToString(i, 2);
Console.WriteLine(str);
//try{} catch(){}捕获异常,并处理
try
{
//checked 检测溢出,如果数据溢出就throw异常
//unchecked 不检测溢出
uint y = unchecked(++i);
Console.WriteLine(i);
}
catch (OverflowException e)
{
//上面如果是不检测溢出,下面就不会捕获异常
Console.WriteLine("There is Overflow!");
}
//checked 和 unchecked 可以包含代码块
//效果则是检不检测throw异常
checked
{
try
{
uint y = unchecked(++i);
Console.WriteLine(i);
}
catch (OverflowException e)
{
Console.WriteLine("There is Overflow!");
}
}
internal class Program
{
static void Main(string[] args)
{
//unsafe 不安全的,后面跟{},里面的代码块就是不安全的代码
unsafe
{
//sizeof 过去结构体存储内存的字节数
int i = sizeof(Student);
Console.WriteLine(i);
}
}
}
//struct 申明结构体
struct Student
{
int UID;
long Score;
}
internal class Program
{
static void Main(string[] args)
{
//unsafe 不安全的,后面跟{},里面的代码块就是不安全的代码
unsafe
{
Student stu;
stu.UID = 1;
stu.Score = 99;
//& 取引用,获取实例的内存地址
Student* pStu = &stu;//获取stu的内存地址
//-> 通过箭头操作指针
pStu->UID = 2;
//* 取引用,引用实例,这样就可以使用.操作符了
//需要注意的是. 操作符比* 操作符优先级高
(*pStu).Score = 100;
Console.WriteLine("Studnet UID:{0}, Score{1}",stu.UID,stu.Score);
}
}
}
//struct 申明结构体
struct Student
{
public int UID;
public long Score;
}
// is 检查变量引用的实例是否为指定类的实例,返回布尔值
Human human = new Human();
Console.WriteLine(human is Human);
// 也就是说当变量引用的为null时,则为false
Human human2 = null;
Console.WriteLine(human2 is Human);
// 当 is 指向是父类或基类也为True
Human human3 = new Human();
Console.WriteLine(human3 is Animal);
Object obj = new Human();
Console.WriteLine(obj is Human);
//当需要转化对象的类型属于转换目标类型或者转换目标类型的派生类型时,那么此转换操作才能成功,而且并不产生新的对象
//【当不成功的时候,会返回null】
object obj2 = new Human();
Console.WriteLine(obj2 as Human);
Console.WriteLine(human as Human);
Console.WriteLine(human2 as Human);
Console.WriteLine(human3 as Human);
int x = 3;
int y = 4;
double a = 20.5;
double b = 25.4;
//&& 条件与,与,并且
//&& 条件与,一方为false,则为false
if (x < y && a < b)
{
Console.WriteLine("&& 条件与,与,并且");
Console.WriteLine("&& 条件与,一方为false,则为false");
}
//|| 条件或,或者,一方为true 则为true
if (a > b || x < y)
{
Console.WriteLine("|| 条件或,或者,一方为true 则为true");
}
//&& || 条件与和或都存在短路效应,即一侧判断结果足以得出结果则不再往下执行
//如 && 左侧一开始就是false,右侧是表达式则不会执行
//|| 左侧一开始就是true,则右侧不会被执行
int i = 0;
if (true && i++ > 0)
{}
Console.WriteLine(i);
i = 0;
if (true || i++ > 0)
{ }
Console.WriteLine(i);
//Nullable<数据类型> 可空变量(泛型)
Nullable<int> i = null;
//.HasValue 获取一个Nullable<>是否有值的布尔值
Boolean b = i.HasValue;
Console.WriteLine(b);
Console.WriteLine(i == null);
//int? 等效与 Nullable<int> 一种简记法
int? j = null;
Console.WriteLine(j.HasValue);
Console.WriteLine(j.Value);//.Value 属性值
j = i ?? 59;// i ?? 59 如果i为null值将59赋值给左边,不是则将i的值赋值给左边
Console.WriteLine(j);
來自 https://www.runoob.com/csharp/csharp-operators.html
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 |
关系运算符
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为真。 | (A == B) 不为真。 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A > B) 不为真。 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 | (A < B) 为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A >= B) 不为真。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A <= B) 为真。 |
逻辑运算符
运算符 | 描述 | 实例 |
---|---|---|
&& | 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 | (A && B) 为假。 |
|| | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 | (A || B) 为真。 |
! | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 | !(A && B) 为真。 |
位运算符
运算符 | 描述 | 实例 |
---|---|---|
& | 如果同时存在于两个操作数中,二进制 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 |
赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | 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 |
其他运算符
运算符 | 描述 | 实例 |
---|---|---|
sizeof() | 返回数据类型的大小。 | sizeof(int),将返回 4. |
typeof() | 返回 class 的类型。 | typeof(StreamReader); |
& | 返回变量的地址。 | &a; 将得到变量的实际地址。 |
* | 变量的指针。 | *a; 将指向一个变量。 |
? : | 条件表达式 | 如果条件为真 ? 则为 X : 否则为 Y |
is | 判断对象是否为某一类型。 | If( Ford is Car) // 检查 Ford 是否是 Car 类的一个对象。 |
as | 强制转换,即使转换失败也不会抛出异常。 | Object obj = new StringReader(“Hello”); StringReader r = obj as StringReader; |
优先级
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 |
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | << >> | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | | | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | || | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=>>= <<= &= ^= |= | 从右到左 |
逗号 | , | 从左到右 |
來自 https://www.runoob.com/csharp/csharp-operators.html
表达式
任何能得到值的运算就是表达式,C#中所有的操作符就是为了组成表达式。
internal class Program
{
static void Main(string[] args)
{
Student student = new Student();
//.成员访问操作符表达式值的类型和成员有关
Console.WriteLine(student.uid.GetType().FullName);
Console.WriteLine(student.name.GetType().FullName);
//f()方法访问操作符的表达式值的类型与方法返回值有关
Console.WriteLine(student.GetScore().GetType().FullNa
//a[x]元素访问操作符的表达式值的类型与元素有关
List<int> list = new List<int> { 1, 2, 3 };
Console.WriteLine(list[0].GetType().FullName);
double[] arr = new double[] { 1.0, 2.0, 3.0 };
Console.WriteLine(arr[0].GetType().FullName);
int i = 10;
//自增、自减 表达式的类型就是表达式值的类型
Console.WriteLine(i++.GetType().FullName);
Console.WriteLine(i--.GetType().FullName);
Console.WriteLine((++i).GetType().FullName);
Console.WriteLine((--i).GetType().FullName);
//new 操作符的表达式的值的类型就是对象的类型
Console.WriteLine(new Form().GetType().FullName);
//default 操作符的表达式的值的类型是被操作数的类型
var temp = default(Int32);
Console.WriteLine(temp.GetType().FullName);
//checked 操作符的表达式的值的类型是被操作数的类型
var x = checked(100.0+200.0);
Console.WriteLine(x.GetType().FullName);
var y = 4.0 / 3;
Console.WriteLine(y.GetType().FullName);
//?: 三元运算符表达式值的类型区精度高的
var z = 5 > 3 ? 10 : 20.0f;
Console.WriteLine(z.GetType().FullName);
}
}
class Student
{
public uint uid;
public string name;
public Student()
{
this.uid = 0;
this.name = "";
}
public int GetScore()
{
return 100;
}
}
语句
语句是高级语言的语法–编译语言和机械语言只有命令(高级语言中的表达式则对应低级语言中的指令),语句等价一个或者一组有明显逻辑关联的指令。
虽然语句是固定的,但是它可以根据输入的不同而选择分支
string str = Console.ReadLine();
double result = 0;
bool flag = double.TryParse(str,out result);//tryParse() 尝试解析
if (flag)
{
Console.WriteLine("result:"+result);
}
else
{
Console.WriteLine("not is number!");
}
C#中有标签语句、申明语句和嵌入式语句。
C# 中语句处理顺序执行,还可以通过判断、跳转和循环来控制程序的走向。
语句的功能:陈述算法思想、控制逻辑走向,完成有意义的操作。
C#语言的语句事宜;结尾,但是以分号结尾的不一定是 语句。[充分不必要]
C#语句一定是在方法体里的。
不是所有表达式都能作为语句使用,如 x + y 和 x == 1这类只计算一个值,然后会被丢弃的、不使用的表达式不能作为语句使用。
块
block用于只允许使用单条语句的上下文中编写多条语句。
block
{[statement-list]}
块语句会被当做一条语句,快语句是一条完整的语句。
if语句
if 语句也是嵌入式语句,嵌入式语句包含if语句
//if (布尔表达式) 嵌入式语句
//if后面只能跟一条嵌入式语句
if (true) Console.WriteLine("OK");
//{}块语句也是嵌入式语句的一种
int x = 10;
int y = 20;
if (x < y)
{
Console.WriteLine("Hello");
Console.WriteLine("World");
}
//if (布尔表达式) 嵌入式语句 else 嵌入式语句
if (x > y)
{ Console.WriteLine("YES"); }
else
{ Console.WriteLine("No"); }
//因为if语句是嵌入式语句的一种,嵌入式语句包含if语句
//所以可以if语句嵌套if语句
int score = 100;
if (score >= 0 && score <= 100)
{
if (score <= 60)
{
Console.WriteLine("不合格");
}
else
{
Console.WriteLine("合格");
}
}
else
{ Console.WriteLine("input Error!"); }
//因为if语句算是一条语句,所以else后面的括号省去,直接接下一个if语句也是可以的。这样就形成了常用的if else if else语句
int score = 80;
if (score >= 0 && score <= 60)
{
Console.WriteLine("不合格");
}
else if (score >= 0 && score <= 80)
{
Console.WriteLine("B");
}
else if (score >= 0 && score <= 100)
{
Console.WriteLine("A");
}
else
{ Console.WriteLine("Input Error!"); }
switch语句
// switch (条件表达式) {}
// 条件表达式 可以是整数、字符、字符串、布尔、枚举和它们对应的可控类型,不能是浮点类型
// case 后面必须跟一个常量,不能是变量。
//
int score = 100;
switch (score / 10)
{
case 10:
if (score == 100)
{
goto case 8;
}
else
{
goto default;
}
case 9:
case 8:
Console.WriteLine("A");
break;
case 7:
case 6:
Console.WriteLine("B");
break;
case 5:
case 4:
Console.WriteLine("C");
break;
case 3:
case 2:
case 1:
case 0:
Console.WriteLine("D");
break;
default:
Console.WriteLine("Error!");
break;
}
try语句
try语句提供了一种机制,用于捕捉在块语句的执行期间发生的各种异常。此外,try语句还能让您指定一个代码块,并保证当控制离开try语句时,总时先执行改代码。
有三种可能的try语句形式:
- 一个try块后接一个或者多个catch块。
- 一个try块后接一个finally块。
- 一个try块后接一个或者多个catch块,后面再接一个finally块。
static void Main(string[] args)
{
//捕捉add抛出的异常
try
{
int result = Add("120000000000000", "10");
Console.WriteLine(result);
}
catch (OverflowException e)
{
Console.WriteLine("Main:"+e.Message);
}
}
public static int Add(string argu1, string argu2)
{
int a = 0;
int b = 0;
//try 块中出现异常会被后面合适的catch捕捉
try
{
a = int.Parse(argu1);
b = int.Parse(argu2);
}
//catch {} 这种catch不管什么异常都捕捉
//catch (异常) {} 只捕捉指定的异常和指定异常的派生类异常
//假如第一个catch已经捕捉了异常,那么他后面那些catch就不会执行。直接跳到finally执行。
catch (ArgumentNullException argu)
{
Console.WriteLine(argu.Message);
}
catch (FormatException form)
{
Console.WriteLine(form.Message);
}
catch (OverflowException over)
{
//throw 抛出异常,谁调用谁处理。
throw over;
}
//finally 不管会不会发生异常finally块都会执行
finally
{
}
return checked(a + b);
}
while语句
while语句在true条件下执行一个嵌入式语句。
while (条件表达式) 循环体
int score = 0;
bool flag = true;
while (flag)
{
Console.WriteLine("Please input first number:");
string str1 = Console.ReadLine();
int x = int.Parse(str1);
Console.WriteLine("Please input second number:");
string str2 = Console.ReadLine();
int y = int.Parse(str2);
int sum = x + y;
if (sum == 100)
{
Console.WriteLine("{0} + {1} = {2}", x, y, sum);
score++;
}
else
{
Console.WriteLine("Error: {0} + {1} = {2}", x, y, sum);
flag = false;
}
}
Console.WriteLine("Your score is {0}",score);
Console.WriteLine("game over!");
do语句
do语句按不用条件执行一个嵌入式语句一次或者多次。
do 循环体 while (条件表达式)
int score = 0;
int sum = 0;
do
{
Console.WriteLine("Please input first number:");
string str1 = Console.ReadLine();
int x = int.Parse(str1);
Console.WriteLine("Please input second number:");
string str2 = Console.ReadLine();
int y = int.Parse(str2);
sum = x + y;
if (sum == 100)
{
Console.WriteLine("{0} + {1} = {2}", x, y, sum);
score++;
}
else
{
Console.WriteLine("Error: {0} + {1} = {2}", x, y, sum);
}
} while (sum == 100);
Console.WriteLine("Your score is {0}", score);
Console.WriteLine("game over!");
break语句
break语句打断当前循环。
int score = 0;
int sum = 0;
do
{
Console.WriteLine("Please input first number:");
string str1 = Console.ReadLine();
if (str1.ToLower() == "end")
{
break;
}
int x = 0;
try
{
x = int.Parse(str1);
}
catch
{
Console.WriteLine("Frist number has problem Restrat!");
continue;
}
Console.WriteLine("Please input second number:");
string str2 = Console.ReadLine();
if (str2.ToLower() == "end")
{
break;
}
int y = 0;
try
{
y = int.Parse(str2);
}
catch
{
Console.WriteLine("Second number has problem Restrat!");
continue;
}
sum = x + y;
if (sum == 100)
{
Console.WriteLine("{0} + {1} = {2}", x, y, sum);
score++;
}
else
{
Console.WriteLine("Error: {0} + {1} = {2}", x, y, sum);
}
} while (sum == 100);
Console.WriteLine("Your score is {0}", score);
Console.WriteLine("game over!");
continue语句
continue跳入下次循环。
int score = 0;
int sum = 0;
do
{
Console.WriteLine("Please input first number:");
string str1 = Console.ReadLine();
int x = 0;
try
{
x = int.Parse(str1);
}
catch
{
Console.WriteLine("Frist number has problem Restrat!");
continue;
}
Console.WriteLine("Please input second number:");
string str2 = Console.ReadLine();
int y = 0;
try
{
y = int.Parse(str2);
}
catch
{
Console.WriteLine("Second number has problem Restrat!");
continue;
}
sum = x + y;
if (sum == 100)
{
Console.WriteLine("{0} + {1} = {2}", x, y, sum);
score++;
}
else
{
Console.WriteLine("Error: {0} + {1} = {2}", x, y, sum);
}
} while (sum == 100);
Console.WriteLine("Your score is {0}", score);
Console.WriteLine("game over!");
for语句
for语句计算一个初始值表达式序列,然后当某个值为真时,重复执行相关的嵌入式语句并计算一个迭代表达式序列。
for (int i = 1; i < 10; i++)
{
for (int j = i; j < 10; j++)
{
Console.Write("{0}*{1}={2} ", i, j, i * j);
}
Console.WriteLine();
}
foreach语句
foreach语句用于枚举一个集合的元素,并对该集合中的每个元素执行一次嵌入式语句。
//实现IEnumerator接口的可以使用接口
int[] arr = new int[] {1,2,3,4,5,6,7,8,9,10};
//获取接口对象,通过数组的GetEnumerator()方法
IEnumerator enumerable = arr.GetEnumerator();
//MoveNext 指针向下移动,可移动返回true,不可移动返回false
while (enumerable.MoveNext())
{
Console.WriteLine(enumerable.Current);
}
//Reset 将指针复位至起点
//(指针起点是指向第一个元素的上一个的,一般是空的,具体实现方法和逻辑。)
enumerable.Reset();
//foreach (声明变量 in 集合) {嵌入式语句}
foreach (var item in arr)
{
Console.WriteLine(item);
}
return语句
return语句将方法中的值返回给调用者。
static void Main(string[] args)
{
Greeting("HeiRen");
}
static void Greeting(string name)
{
//字符串为空或者null时,提前使用return退出方法。
if (string.IsNullOrEmpty(name)) return;
Console.WriteLine("Hello {0}!",name);
}
字段
概述
字段(fixed)是一种表示与对象或类型(类与结构体)关联的变量
字段是类型的成员,旧称“成员变量”
与对象关联的字段成为“实例字段”
与类型关联的字段成为“静态字段”,有static关键字修饰
声明
字段声明分号结尾,但字段申明不是语句。
字段的名字一般都是名词。
修饰符 数据类型 变量 初始化器
public int age = 0;
在声明时初始化和在构造函数初始化是相同的。
实例字段是被实例化时初始化,静态字段则是在加载这个类时初始化。
静态字段只会被初始化一次,就是类被第一次加载时。
class Student
{
public int age;
public string name;//public 公共的
private int score;//private 私人的
public readonly uint Uid;//readonly只读
readonly public static string str;//修饰符没有顺序
//实例字段的构造函数
public Student()
{ }
//静态字段的构造函数
static Student()
{ }
}
属性
概述
属性时字段的包装器。
属性 (property)是一种用于访问对象或类的特征的成员,特征反映了状态。
属性是字段的自然扩展
-
从命名上看,fixed更偏向于实例对象在内存的布局,property更偏向与反映现实世界对象的特征。
-
对外:暴露数据,数据可以是存储在字段里,也可以是动态计算出来的。
-
对内:保护字段不被非法值“污染”。
又是一个“语法糖”
声明
快速声明
快捷键 Ctrl + R,Ctrl +E
修饰符 返回值 属性名{get; set;}
修饰符 返回值 属性名{get{} set{}}
//完整声明
private bool Sex;//如果没有声明字段,那么属性就不会包装字段
public bool Sex
{
get { return Sex; }
set { Sex = value; }
}
//简便声明
public int Score { get; set; }
class Student
{
//私人的
private int Age;
//get方法
public int GetAge()
{
return this.Age;
}
//set方法,保护字段的数据安全,防止被错误的数据污染
public void SetAge(int age)
{
if (age < 0 || age > 120)
{
throw new Exception("Age value has error!");
}
this.Age = age;
}
//属性,保护字段的数据安全为属性
//修饰符 返回值 属性名{get{} set{}}
public int age
{
get { return this.age; }
set
{
//value 指属性形参,把它当作形参用就行
//value 上下文关键字,在特定的坏境才是关键字
if (value < 0 || value > 120)
{
throw new Exception("Age value has error!");
}
this.age = value;
}
}
//只有set的属性为只写属性,没有什么用,因为属性本身就是为了暴露数据给外界的。
public string Uid
{
set { this.Uid = value; }
}
//只有get的属性为只读属性
public string Name
{
get { return this.Name; }
}
}
Student student = new Student();
//调用属性不用get set,一样时受属性的get set方法约束的
student.Age = -1;
Console.WriteLine(student.Age);
索引器
索引器是这样一种成员,它使对象能够用与数据相同的方式(即使用下标)进行索引。
一般用于集合类。
internal class Program
{
static void Main(string[] args)
{
Student stu = new Student();
Console.WriteLine(stu["key"] == null);//获取值
//赋值
stu["Math"] = 100;
Console.WriteLine(stu["Math"]);
}
}
class Student
{
Dictionary<string,int> dic = new Dictionary<string,int>();
//public value类型 this[key类型]{get{} set{}}
public int? this[string key]
{
get {
if (dic.ContainsKey(key))
{
return dic[key];
}
else
{
return null;
}
}
set {
if (!value.HasValue)
{
throw new Exception("Score cannot be null.");
}
if (dic.ContainsKey(key))
{
dic[key] = value.Value;
}
else
{
dic.Add(key,value.Value);
}
}
}
}
常量
概述
常量(constant)是表示常量值(即,可以在编译时计算的值)的类成员
-
常量隶属于类型而非对象,即没有实例常量。
-
实例常量的角色由只读实例字段来担当。
-
注意区分成成员常量与局部变量。
常量的声明
const 类型 变量名 初始化器;
const double PI = 3.14159265;
各种只读的应用场景
为了提高程序可读性和执行效率–常量
为了防止对象的值被修改–只读字段
向外暴露不允许修改的数据–只读属性(静态或者非静态的),功能和常量部分重叠。
当希望成为常量的值类型不能被常量声明时接受(类或自定义结构体)–静态只读字段。因为常量只能用作值类型。所有如果是引用类型那就只能用静态只读字段了。
参数
传值参数
传值参数 -> 值类型
- 值参数创建变量的副本
- 对值参数的操作永远 不影响变量的值(string类型相同)
static void Main(string[] args)
{
int j = 0;
Add(0);
Console.WriteLine("Main:{0}",j);
}
//传值参数 int i 传的是值类型
//如果传值参数传的是值类型,那么它会创建一个副本。互不干扰。
public static void Add(int i)
{
i++;
Console.WriteLine("Add:{0}",i);
}
传值类型 -> 引用类型
internal class Program
{
static void Main(string[] args)
{
Student stu = new Student() { Name = "李四" };
setStuName(stu);
Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name);
}
//传值参数,传的是引用参数时,实际是传递引用的推地址
//简单来说就是创建了一个新的指针指向了原来的推地址
static void setStuName(Student stu)
{
stu.Name = "张三";
Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name);
}
}
class Student
{
public string Name { get; set; }
}
输出参数
引用参数
数组参数
具名参数
可选参数
扩展参数(this参数)
反编译器
1.打开Developer PowerShell for VS 2022
2.输入lidasn
3.File
-> Open
-> 打开exe文件
书写习惯
**书写方法遵守单一职责原则。**即一个方法只完成一件事情。
常用属性或方法
GetType()//获取当前实例的类型
GetType().Name//类型名称
Type mType = typeof(Form);//获取Type对象
mType.BaseType;//获取父类的Type对象
mType.FullName;//获取该类的类全称,包括命名空间,不包含程序集
PropertyInfo[] p = mType.GetProperties(); //获取所有公有属性
MethodInfo[] m = mType.GetMethods();//获取所有公有方法
double a = double.PositiveInfinity;//正无穷大
double b = double.NegativeInfinity;//负无穷大
//Nullable<数据类型> 可空变量(泛型)
Nullable<int> i = null;
int? j = null;//简写
//.HasValue 获取一个Nullable<>是否有值的布尔值
Boolean b = i.HasValue;
string.Empty //获取一个空的字符串
糖衣炮弹(语法糖)
值类型? 变量名 初始化器;
int? i = null;