#Region 这些代码实现了折叠功能
#EndRegion
int n1 = 10;
int n2 = 20;
int n3 = 30;
Console.WriteLine("first number:{0};second number:{1};third number:{2}",n1,n2,n3);//10 20 30
Console.WriteLine("first number:{1};second number:{0};third number:{2}", n1, n2, n3);//20 10 30
int a = 10;
int b = 3;
double c = a * 1.0 / b;
Console.WriteLine("{0:0.00}",c); //这个占位符靓哦,这样就不会输出3.33333333...而是输出3.33
转义符指的是一个"\"+一个特殊的字符,组成了一个具有特殊意义的字符,
@符号:1.取消\在字符串中的转义作用,2.将字符串按照原格式输出
string s="123";
int a=int.Parse(s);
int b=Convert.ToInt32(s);
string s = "123aaa";
int n1 = int.Parse(s);//抛出异常
int n2 = Convert.ToInt32(s);//抛出异常
int n;
bool b1 = int.TryParse(s,out n);//不抛出异常,b1是false,n=0
bool b2 = int.TryParse("123", out n);//不抛出异常,b1是true,n=123
namespace ConsoleApp4
{
//一般将枚举声明到命名空间的下面,类的上面,表示这个命名空间里的所有类都可以使用这个枚举
public enum Gender
{
Male,
Female,
}
class Program
{
static void Main(string[] args)
{
char gender1 = '男';
string gender2 = "man";
string gender3 = "爷们";
//由于开发者的个性,对性别有不同的定义,将多个开发者的代码整合到一块时可能会出现错误,所以枚举起到了规范代码开发的作用
Gender gender = Gender.Male;
}
}
}
namespace ConsoleApp1
{
public enum Season//枚举类型可以和int类型互换,枚举类型和int类型是兼容的
{
spring,
summer,
autumn,
winter
}
class Program
{
static void Main(string[] args)
{
int n = (int)Season.summer;//枚举->int n=1
string s = Season.spring.ToString();//枚举->string s="spring"
Season season = (Season)2;//int->枚举 season=autumn
string s1 = "2";//s1="2"与s1="spring",输出的值是一样的
Season season1 = (Season)Enum.Parse(typeof(Season), s1);//string->枚举 season1=autumn
}
}
}
public
同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。
private
只有同一类或结构中的代码可以访问该类型或成员。
protected
只有同一类或结构或者此类的派生类中的代码才可以访问该类型或成员。
internal
同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。
命名空间下元素的默认访问修饰符:命名空间下只能使用两种访问修饰符public和internal。命名空间下的枚举和结构体默认修饰符为public,类,接口默认为internal
各类型中成员的访问修饰符:
类中所有的成员,默认均为private,当然也可以修改成其它的访问修饰符。
接口的成员默认访问修饰符是public,也不可能是其他访问修饰符。
枚举类型成员默认public,也不可能是其他访问修饰符。
委托,默认的是internal 。
namespace ConsoleApp1
{
//结构可以帮助我们一次声明多个不同类型的变量
struct Student//结构和枚举的默认访问权限为public
{
public string _name;//结构成员默认访问权限为private,枚举默认访问权限为public
public int _age; //name,age,gender是字段,光标放到上面会有提示,变量不可以用修饰符修饰,字段可以
public Gender _gender;
} //为了区分字段与变量字段前会加"_"
enum Gender
{
male,
female
}
class Program
{
static void Main(string[] args)//如果一个学校有2000个学生需要声明6000个变量,有了结构只需声明2000个变量
{
Student student1 = new Student();
student1._name = "tang-san";
student1._age = 16;
student1._gender = Gender.male;//枚举与结构本质上都是变量
}
}
}
类加载的时候,所有的静态类及其静态成员就会被创建在“静态存储区”里面,一旦创建直到程序退出,才会被回收
静态类中只允许有静态成员,不允许有实例成员
静态成员是属于类的,实例成员是属于对象的
静态成员必须使用类名去调用,而实例成员使用对象名调用
静态函数中只能访问静态成员,不能访问实例成员
实例函数中既可以访问静态成员,也可以访问实例成员
如果把一个类当做“工具类”去使用,这个时候可以考虑将其写成静态类,静态类在整个项目中资源共享。
namespace ConsoleApp1
{
class Program
{
public static int n = 0;
public Program()
{
n = 1;
}
static Program()//静态构造函数只执行一次,所以静态构造函数中不允许出现访问修饰符
{
n = 2;
}
static void Main(string[] args)
{
Console.WriteLine(n);//n=2,因为在类加载时静态构造函数执行了
Program program = new Program();
Console.WriteLine(n);//n=1,因为实例化时构造函数执行了
}
}
}
在一个方法中返回多个相同类型的值时可以考虑使用数组,当返回多个不同类型的值时,就要使用out
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] nums = new int[9] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int max;
int min;
string result;
FinderValues(nums,out max,out min,out result);
}
static void FinderValues(int[] nums,out int max,out int min,out string result)
{
min = nums[0];
max = nums[0];
for(int i = 0; i < nums.Length; i++)
{
if (min > nums[i]) min = nums[i];
if (max < nums[i]) max = nums[i];
}
result = "找值完成";
}
}
}
能够将一个变量带入一个方法中更改,改变完成后再将改变后的变量带出方法
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int salary = 5000;
JiangJin(ref salary);
Console.WriteLine(salary);//输出5500
FaKuan(ref salary);
Console.WriteLine(salary);//输出5000
}
static void JiangJin(ref int salary)
{
salary += 500;
}
static void FaKuan(ref int salary)
{
salary -= 500;
}
}
}
将实参列表中跟可变参数数组一致的元素都当做数组的元素去处理。
params必须是形参列表中的最后一个元素。
class Program
{
static void Main(string[] args)
{
string name = "xiao-wu";
int[] scores = new int[] { 90, 94, 92 };
TotalScore(name, scores);
//TotalScore(name, 90, 94, 92 );//这样也可以哦!
Console.ReadKey();
}
static void TotalScore(string name,params int[] scores)
{
int sum = 0;
for(int i = 0; i < scores.Length; i++)
{
sum += scores[i];
}
Console.WriteLine("{0}的总成绩是{1}",name,sum);
}
}
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
TellStory();
Console.ReadKey();
}
static void TellStory()
{
Console.WriteLine("从前有座山,山上有座庙,庙里老和尚给小和尚讲故事,");
TellStory();
}
}
}
类和结构是不同的,类是面向对象的,面向对象的三个特征封装、继承、多态,结构一个也没有,结构是面向过程(强调干什么)。(类和结构都可拥有结构、字段、属性和方法)
构造函数是特殊的方法,在实例化对象的时候被执行
1)代表当前类的对象
2)在类中显式的调用本类的构造函数
public class Student
{
public string Name { get; set; }//自动属性
public int Age { get; set; }
public string Address { get; set; }
public Student(string name,int age,string address)
{
Name = name;
Age = age;
Address = address;
}
public Student(string name,int age):this(name,age,"河南")
{
//this表示调用本类的构造函数
}
}
值类型:int、double、decimal、char、bool、enum、struct
引用类型:类、数组、接口
栈、堆、静态存储区域
不需要额外的代码,计算机自动完成转换,适用于取值范围小的数据类型转换为取值范围大的数据类型。
又称强制转换,需要编写代码才能完成转换,适用于取值范围大的数据类型转换为取值范围小的数据类型。
我们可能会在一些类中,写一些重复的成员,我们可以将这些重复的成员单独封装到一个类中,作为这些类的父类。
1)继承的单根性:一个子类只能有一个父类
2)继承的传递性:
子类没有继承父类的构造函数(因为子类无法调用父类的构造函数)。实例化子类时子类会默认调用父类的无参的构造函数先实例化父类,父类实例化之后子类才能使用父类中的成员。如果在父类中重新写了一个有参的构造函数后,那个无参的就被干掉了,实例化子类时子类就掉用不到了,此时就会报错。
解决方法:
1)在父类中重新写一个无参的构造方法;
2)在子类显式的调用父类的构造方法,使用关键字base()
1)创建对象
2)隐藏从父类那里继承过来的同名成员
1)子类可以赋值给父类:如果有一个地方需要一个父类作为参数我们可以给一个子类参数代替
2)如果父类对象中装的是子类对象,我们可以将这个父类对象强转成子类对象
子类对象可以调用父类的成员,但是父类对象永远只能调用自己的成员
接口、抽象类等父类对象(包括里面有虚方法的类)可以调用实现接口、抽象类的子类中的实现成员(包括在子类中重写虚方法的成员)及其父类本身的成员,子类中的其他成员不允许调用。
is表示类型转换 如果可以转换返回true,不可以转换返回一个false
as表示类型转换 如果转换成功则返回对应的对象,转换失败返回null
编码:就是数据以什么方式的二进制存储在计算机中。
编码方式:美国ASCII 、中国 GBK等, 各国都有自己的编码方式
乱码的原因:将数据转化成二进制进行保存时使用的编码方式和将二进制转化成数据使用的编码方式不同。
类:引用类型 值分配在内存的堆中
结构:值类型 值分配在内存的栈中
相同点:类和结构中,如果字段前不加访问修饰符,默认为private
不同点:在类的构造函数中,你既可以给字段赋值、也可以给属性赋值,而在结构的构造函数中你只能给字段赋值;在类中构造函数可以有重载,而在结构中构造函数不可以有重载(就是在结构中的构造函数必须给所有的字段赋值,在类中的构造函数可以不用给所有的字段赋值);类中的new是在堆中开辟空间创建对象和执行构造函数,结构中的new只是执行构造函数;在类中如果写了一个构造函数(不管是有参的还是无参)默认的无参构造函数就会被干掉,在结构中如果写了一个有参数的构造函数,无参的构造函数不会被干掉,也就是在结构中最多只能有两个构造函数一个是无参的,一个是全参的,类中的构造函数可以有很多个因为他可以重载。
类的成员“纵向扩展”(行为改变,版本增高)
重写与隐藏发生的条件:
函数成员(方法,属性,事件等)可见、签名一致。
public class Vehical
{
public virtual void Run()
{
Console.WriteLine("Vehical is running");
}
}
public class Car: Vehical
{
public override void Run()
{
Console.WriteLine("Car is running");
}
}
public class RaceCar1:Car
{
public new void Run() //new隐藏了Car.Run()
{
Console.WriteLine("RaceCar is running");
}
}
public class RaceCar2 : Car
{
public override void Run() //override重写了Car.Run()
{
Console.WriteLine("RaceCar is running");
}
}
public class RaceCar3 : Car
{
}
class Program
{
static void Main(string[] args)
{
Vehical v = new RaceCar1();
v.Run(); //Car is running
((Car)v).Run(); //Car is running
((RaceCar1)v).Run(); //RaceCar is running
v = new RaceCar2();
v.Run(); //RaceCar is running
((Car)v).Run(); //RaceCar is running
((RaceCar2)v).Run(); //RaceCar is running
v = new RaceCar3();
v.Run(); //Car is running
((Car)v).Run(); //Car is running
((RaceCar2)v).Run(); //Car is running
Console.ReadKey();
}
}
基于重写机制(virtual/abstract->override)
父类对象引用子类对象,父类行为由最新版本决定(如上图)
抽象修饰符abstract可以与类,方法,属性,事件和索引器一起使用。
一般类->抽象类->接口:越来越抽象,内部实现的东西越来越少
抽象类是未完全实现逻辑的类,内部有未实现的方法、属性、事件或索引器。
封装确定的,开放不确定的,下推到合适的子类中去实现
抽象类为复用而生:专门作为基类来使用,也具有解耦的功能
接口是完全未实现逻辑的类,是“纯虚类”。接口里的成员可以是方法、属性、事件或索引器。成员全部为public
接口为解耦而生,“高内聚,低耦合”,方便单元测试。
接口和抽象类都不能实例化,只能用来声明变量,引用具体类的实例。
抽象类:一个类里面一旦有了 abstract 成员,类就变成了抽象类,就必须标 abstract。
abstract 成员即暂未实现的成员,因为它必须在子类中被实现,所以抽象成员不能是 private 的。
因为抽象类内部还有未实现的成员,计算机不知道怎么调用这类成员,于是编译器干脆不允许你实例化抽象类。
一个类不允许实例化,它就只剩两个用处了:
a.作为基类,在派生类里面实现基类中的 abstract 成员
b.声明基类(抽象类)类型变量去引用子类(已实现基类中的 abstract 成员)类型的实例,这又称为多态
virtual(虚方法)还是有方法体的,只不过是等着被子类重写 ;abstract(纯虚方法)却连方法体都没有。
开闭原则:我们应该封装那些不变的、稳定的成员,而把那些不确定的,有可能改变的成员声明为抽象成员,并且留给子类去实现。
1. 因为 interface 要求其内部所有成员都是 public 的,所以就把 public 去掉了
2. 接口本身就包含了“是纯抽象类”的含义(所有成员一定是抽象的),所以 abstract 也去掉了
3. 因为 abstract 关键字去掉了,所以实现过程中的 override 关键字也去掉了
已完结,此博文之后仍会继续更新,希望大家的持续关注