C#基础知识(停止更新、移步博客园)
搬家到博客园了,博客园地址
C# 基础
- 搬家到博客园了,博客园地址
- VS快捷键
- 一、预备节
- 二、数组
- 2.1. 声明并初始化:
- 2.2. 数组赋值(别名):
- 2.3. *多维数组(矩阵)*:
- 2.4. 交错数组(数组嵌套):
- 2.5. 传递数组给函数
- 2.6. 参数数组
- 2.7 Array类
- 三、类与接口
- 3.0 字段、属性与方法
- 3.1. static静态 (上升至类级别)
- 3.2. 类的定义及实例化
- 3.3. 类的访问级别
- 3.4. 继承
- 3.5. 重写与多态(虚方法)
- 3.6 抽象类与接口
- 3.7 扩展方法
- 3.8 反射与依赖注入
- 3.9 嵌套类(内部类)
- 3.9.1 内类访问外类
- 3.9.2 内部类的实例化
- 四、委托
- 4.1. Func & Action 委托
- 4.2 自定义delegate 委托
- 4.2.1 声明自定义委托类型
- 4.2.2 创建委托对象
- 4.2.3 委托组合(多播委托)
- 4.2.4 委托方法添加 & 移除
- 4.2.5 委托调用
- 4.3 匿名方法
- 4.4 Lambda表达式(*也是匿名方法*)
- 五、事件
- 5.1 含义
- 5.2 五个组成部分
- 5.3 事件作用范围与功能
- 5.4 事件声明
- 5.5 事件订阅
- 5.6 事件触发
- 六、泛型
- 6.1 List集合
- 6.2 Dictionary键值对字典
- 6.3 泛型类
- 6.4 where语句(泛型约束)
- 6.5 泛型委托
- 6.6 泛型接口
- 6.7 协变out、逆变in
- 6.7.1 协变
- 七、LINQ
- 八、反射和特征
- 8.1 接口隔离原则
- 8.2 反射
VS快捷键
- F12 跳转到定义处。
- Ctrl+“-” 跳回原处。
- F6 编译。
- F5 debug。
- F11 单步debug运行。
- F10 跨步debug运行。
- 两下tab键,填充目标语句。
- cw填充为Console.WritelLine();
- 自定义构造器(构造函数)“ctor”
- 类成员"prop"
- svm为Main函数
- 在代码上面输入"///"会自动补充注释头
- Ctrl+K+C 上注释,+U解注释
- Ctrl+M+O 折叠所有代码,+L展开所有代码,+M折叠当前代码
一、预备节
@
解除转义:@"C:\Windows"
="C:\\Windows"
将关键字作为标识符使用:int @int = 1;
字符串跨行:string str = "line one"+ "line two"+ "line three"+ "line fore";string str = @"line oneline twoline threeline fore";
$
将字符串转化为“内插字符串”:
输出的变量不需要再用索引输出,直接外加"{}"写在字符串中即可。结构为:
namespace 声明
class声明
class属性与成员声明
Console.ReadLine()
只接受字符串数据。ref int x
中的ref
为引用声明,放在数据类型前面,引用参数是一个对变量的内存位置的引用。foreach (类型 元素 in 数组)
每次将数组的一个赋值给元素。- 可空类型(Nullable):
类型? 变量名 = null;
在现有的数据类型范围基础上加个null。 a ?? b
: a如果为null则返回b。- 日期格式化,见笔记
dynamic
为自动数据类型,根据赋值的不同自动变。typeof(x)
中的x,必须是具体的类名、类型名称等,不可以是变量名称。
.GetType()
方法继承自Object,所以C#中任何对象都具有GetType()方法。- 数据类型分为:值类型 & 引用类型 & 指针类型
引用类型的变量在栈中分配,引用类型的实例在堆中分配。
值类型总是分配在它声明的地方:作为类的字段(成员变量)时,跟随其所属的实例存储,也就是存储在了堆中;作为方法中的局部变量时,存储在栈上。
数组本身是引用类型,但是不管数组存储的元素是值类型还是引用类型,都是存储在堆中。
详见此博客
- 重载:
只要参数列表不同就行,返回值可同可不同!因为仅返回值不同的时候甚至不能通过编译,调用函数时不知道该调用那个,违反了上下文独立性。
区分于“ 重写 (覆盖)”:存在于父子类间的关系。
读数据:
Console.Read()
控制台读一个字符
Console.ReadLine
控制台读一行字符串
c#中键盘录入结果是转换成string类型的,所以输出结果需要转换成相应的数据类型!
形式为:
数据类型.parse(Console.ReadLine());
或者使用:
Convert.ToXXX(str);
隐式转换:
数往大装,类往小装。
字符串拼接
string str = "my name is" + name + "my age is" + age; string str = string.Format("my name is {0},my age is {1}.", name, age); string str = $"my name is {name},my age is {age}.";
二、数组
2.1. 声明并初始化:
int [] array = new int[3];
int [] array = {1,2,3};
int [] array = new int[3]{1,2,3}; //同上
int [] array = new int[]{1,2,3}; //同上
2.2. 数组赋值(别名):
int [] marks = new int[] { 99, 98, 92, 97, 95};
int[] score = marks;
//score 与 marks指向同一内存地址。
2.3. 多维数组(矩阵):
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]; //二维数组访问(第3行第4个)
2.4. 交错数组(数组嵌套):
//92 93 94
//85 66 87 88
int[][] scores = new int[2][]{new int[]{92,93,94},new int[]{85,66,87,88}};
/*
scores 是一个由两个整型数组组成的数组
scores[0] 是一个带有 3 个整数的数组,
scores[1] 是一个带有 4 个整数的数组。
*/
2.5. 传递数组给函数
通过指定不带索引的数组名称来给函数传递一个指向数组的指针。
double getAverage(int[] arr);//1维
double getAverage(int[,] arr)//2维
int getArea(int[][] array);//交错数组
2.6. 参数数组
有时,当声明一个方法时,您不能确定要传递给函数作为参数的参数数目。
C# 提供了 params 关键字,使调用数组为形参的方法时,既可以传递数组实参,也可以传递一组数组元素。
- 带 params 关键字的参数类型必须是一维数组,不能使用在多维数组上
- 不允许和 ref、out 同时使用
- 带 params 关键字的参数必须是最后一个参数,并且在方法声明中只允许一个 params 关键字
- 不能仅使用 params 来使用重载方法
- 没有 params 关键字的方法的优先级高于带有params关键字的方法的优先级
public int AddElements(params int[] arr)
app.AddElements(512, 720, 250, 567, 889);
2.7 Array类
见微软文档
三、类与接口
3.0 字段、属性与方法
字段:类似C++中的成员属性,通常设置为private,并进行封装。
private string name;
属性:分为 “有参属性” 和 “无参属性”。
//(1)原始写法--get、set访问器
public string Name
{get{return name;}set{name = value;}
}//(2)另一种写法
public string Name
{get => name;set => name = value;
}//(3)简略写法
public string Name { get; set;} = 初值
方法:类似C++中的成员方法
3.1. static静态 (上升至类级别)
static 关键字把类成员定义为静态的(静态变量、静态函数),意味着无论有多少个类的对象被创建,只会有一个该静态成员的副本。
静态函数 在对象被创建之前就已经存在,甚至不用实例化就可以使用,但是只能访问静态变量。
static修饰的成员必须通过类来访问。
3.2. 类的定义及实例化
class Student
{public int ID{get;set;}
}
static void Main(string[] args)
{Student stu = new Student(){ID = 1};
}
- 自定义构造器(构造函数)“ctor”:
- 类成员"prop":
3.3. 类的访问级别
internal
:仅限 “项目” 内的访问。<默认>public
:开放。<接口的默认>abstract
:仅限 “项目” 内的访问,该类不能被实例化,只能被继承。public abstract
:开放,该类不能被实例化,只能被继承。sealed
:仅限 “项目” 内的访问,该类不可被继承。public sealed
:开放,该类不可被继承。
3.4. 继承
只能有1个基类,但可以实现多个基接口。(只能有一个亲爹,可能有多个义父)
加上
sealed
限定符的表示 “封闭类” ,不可被继承。基类与派生类:
class 基类 {... } class 派生类 : 基类 {... }
this
&base
访问关键字:
this
:指代引用类的当前实例。
base
:从派生类中访问基类的成员:
详见此博客子类的构造:
访问修饰符 派生类(参数列表) : base(参数列表) {... } //如果父类已经对成员进行赋值了,此构造器内就不需要再赋值一次。
用子类来实例化父类:(多态基础)
父类 实例名 = new 子类();
3.5. 重写与多态(虚方法)
多态:子类需要覆写父类中的方法来实现子类特有的行为。
虚方法: 使用
virtual
和override
关键字实现方法重写:class Animal {public virtual void Run() //父类实例调用Run时,使用父类(跟实例走){ } } class Cat:Animal {public override void Run() //子类实例调用Run时,使用子类{ } }
隐藏基类成员:
相当于子类将父类方法继承下来,但是被本身的方法隐藏。class Animal {public void Run() //由对象类型决定,{ } } class Cat:Animal {public new void Run() // new也可以不写,但是会警报{ } }
虚方法中必须有实现部分。
3.6 抽象类与接口
为了解决多态时基类函数方法模糊、无用的问题,可以将该方法定义为抽象方法,此方法所在的类也必须是抽象类,抽象类不能被实例化,可以有普通方法、虚方法、抽象方法,但是抽象方法只能出现在抽象类中。
抽象方法:与上述虚方法类似,此时用的是
abstract
与override
搭配使用,不提供实现部分,由派生类强制重写,接口:如果是“纯虚类”(只写规范),则可以将抽象类再抽象为接口,降低耦合度。适用于多继承
interface 接口名 {int 属性名;void 方法名(); }
3.7 扩展方法
如果要增加类中的功能 :
1、如果有源码并可以修改类内容,直接加
2、如果不能修改类(比如在一个第三方类库中),只要不是sealed,可以通过派生类增加。
3!、如果不能访问代码 & 这个类是sealed & 有其他设计原因这些方法不适用,就不得不在另一个使用该类的public成员的类中编写拓展方法。
static class ExtendMyAverage //简易扩展,但也就是另一个类使用了MySum类实例当参数
{public static double Average(MySum ms) //MySum 类的实例{return ms.Sum()/3; //使用实例中的public方法}
}//方法调用:
ExtendMyAverage.Average(ms);
如果可以用原来的类自身调用拓展方法将更加符合认知:(就像原来的类自己扩展了方法)
- 新建类必须是static;
- 拓展方法必须是public static的,第一参数必须包含“this 原本类 类的实例”;
static class ExtendMyAverage //第二种方法,类必须是static的,也可以拓展接口
{public static double Average(this MySum ms) //MySum 类的实例,必须是public static的,参数必须包含“this 原本类 类的实例”{return ms.Sum()/3; //使用实例中的public方法}
}//方法调用:就像自己的方法一样。
ms.Average();
3.8 反射与依赖注入
3.9 嵌套类(内部类)
“类种类”
public class Container //外部类
{public class Nested //嵌套类{Nested() { }}
}
3.9.1 内类访问外类
内部类可以访问外部类的所有成员(包括 private 和 protected)
但外部类如果想访问内部类则有限制
public class Container
{public class Nested{private Container parent; //外部类类型public Nested() //D1构造函数{}public Nested(Container parent) //D2构造函数{this.parent = parent;}}
}
3.9.2 内部类的实例化
Container.Nested nest = new Container.Nested();
四、委托
也是一种类。
类似于C++的回调函数(该函数名会被当做参数传给其他函数,从而被别的函数调用)
4.1. Func & Action 委托
Action委托 只能指向返回值为空的函数。
Action 委托名 = new Action(对象.方法名); 委托名.Invoke(); //间接调用类的方法。 委托名(); //效果同上。(函数指针式)
Func委托可以指向有参数有返回值的函数。
Func<参数类型,返回值类型> 委托名 = new Func<返回值类型,参数类型>(对象.方法名); XX = 委托名.Invoke(参数); //间接调用类的方法。 XX = 委托名(参数); //效果同上。(函数指针式)
4.2 自定义delegate 委托
4.2.1 声明自定义委托类型
无需在类的内部声明,因为它是类型声明。
public delegate 返回类型 委托类名(参数签名);
4.2.2 创建委托对象
方法可以被委托包装的限制:
- 签名(参数列表)必须与委托完全一致
- 返回值类型必须与委托一致
委托类名 委托名 = new 委托类名(对象.方法名); //使用 new 创建对象委托类名 委托名 = 对象.方法名; //效果同上,隐式创建委托对象。(常用)
//这种快捷语法可以工作是因为在方法名称和其相应的委托类型之间存在隐式转换。
由于委托是引用类型,类似string,具有不变性,给委托赋值时相当于创建了个新的委托。
4.2.3 委托组合(多播委托)
委托名3 = 委托名1 + 委托名2;
但“委托3”并不会影响“委托1 & 2”.
4.2.4 委托方法添加 & 移除
类似Queue,先进先出。委托不可变,+=、-=实际上是创建了新委托。
委托名 += 对象.方法名; //添加委托名 -= 对象.方法名; //移除(从队尾搜索)
如果调用列表为空,则委托为null。
4.2.5 委托调用
XX = 委托名.Invoke(参数); //间接调用类的方法。XX = 委托名(参数); //效果同上。(函数指针式)
如果委托有返回值:
- 调用列表中最后一个方法返回的值就是委托调用返回的值。
- 调用列表中所有其他方法的返回值都会被忽略。
4.3 匿名方法
C# 2.0引入。
委托类名 委托名 = delegate(参数列表){方法体;};
匿名方法不会显式声明返回值,方法内代码本身行为返回一个类型 = 委托的返回类型
4.4 Lambda表达式(也是匿名方法)
C# 3.0为了简化匿名方法的语法而引入。
MyDel del = delegate(int x) {return x+1;}; //匿名方法MyDel del = (int x)=>{return x+1;}; //Lambda表达式MyDel del = (x)=>{return x+1;}; //同上简易Lambda表达式MyDel del = x => x+1; //一个参数,括号可省略MyDel del = ()=>x+1; //没有参数必须加括号
更简化的写法与限制条件见书《C#图解教程 5th》
五、事件
5.1 含义
因为事件隶属于某个主体。
所以为一种类的成员,这种成员使类或对象具备了通知能力(手机通过响铃使手机具备了通知能力)
防止委托滥用造成程序混乱(只能+=、-=)
本质上是一个委托的包装器,封装了委托。
5.2 五个组成部分
- 发布者(Publisher):发布某个事件的类或者结构。
- 订阅者(Subscriber):注册并在事件发生时得到通知的类或者结构。
- 事件(Event):如上述介绍,被触发才会发挥功能。
- 事件处理器(Event Handler):S注册到事件的方法,在P触发事件时执行。
- 事件注册:把事件与事件处理器关联在一起
5.3 事件作用范围与功能
- 在类内,视为普通委托使用
- 在类外,只能使用+=、-=操作。
5.4 事件声明
- 完整声明:
private XXXEventHandler 委托对象; //用于声明事件的委托对象,含义见下。 public event XXXEventHandler 事件对象 { add{this.委托对象 += value;}remove{ this.委托对象 -= value;} }
- 简略声明:
public event XXXEventHandler 事件对象;
此时编译器会自动生成一个隐藏的委托类型字段。
5.5 事件订阅
常需要声明一个委托来承接这个事件
class XXXEventArgs:EventArgs{属性;}public delegate 返回类型 XXXEventHandler(Publisher类 p对象,XXXEventArgs e); //专门用于事件中使用的委托
或者直接不声明,使用自带的EventHandler(object,EventArgs),并在事件处理程序中先类型转换,在使用参数。
类.事件 += 方法名; //直接法类.事件 += new 委托名(方法名); // 委托形式类.事件 += delegate{方法体}; //匿名方法类.事件 += () => {方法体}; //Lambda
5.6 事件触发
在触发事件之前与null进行比较,从而查看事件是否包含事件处理程序。
- 完整版:
if(XXXEventHandler != null)XXXEventHandler(参数表); //事件触发XXXEventHandler.Invoke(参数表); //或者
- 简略版:
if(事件 != null)事件(参数表) //事件触发
六、泛型
类型的模板
6.1 List集合
可变长度的固定类型集合,代替长度不可变的数组。
List<数据类型> my_list = new List<数据类型>();
my_list.Add(数据);
6.2 Dictionary键值对字典
Dictionary<int,string> dictionary = new Dictionary<int,string>();
6.3 泛型类
//泛型类声明:
class MyClass<T1,T2>
{public T1 XXX;public T2 YYY;
}//类实例化
MyClass<int> demo = new MyClass<int>();
6.4 where语句(泛型约束)
class MyClass<T1,T2,T3> //用where来约束类型参数,多个约束的话用","分隔where T2:Customer //T2只有Customer类型的类或者派生类才能用作类型实参 where T3:IComparable //T3只有实现IComparable接口的类才能用作类型实参
{...
}
6.5 泛型委托
delegate TR 委托<T,TR>(T t);
6.6 泛型接口
interface IMyIfc<T>{ T Func(T t);}
实现接口时必须保证不会出现两个重复的接口:
继承自 IMyIfc< int > 和 IMyIfc< S >时,S可能时int,错误。
6.7 协变out、逆变in
父类是可以用子类来实例化的:class 父 = new 子();
但在下面的例子中是不正确的。
针对泛型接口和泛型委托来说的。
People people = new Teacher(); //正确,因为Teacher继承自People
List<People> peoples = new List<Teacher>(); //错误,因为没有List<People> --> List<Teacher>的继承
6.7.1 协变
七、LINQ
Language Integerated Query — 语言集成查询
八、反射和特征
8.1 接口隔离原则
“胖”接口会导致调用它的类有一些总也用不到的方法需要去实现。
为了解决这个问题需要将接口“拆分”。
最后原本的接口继承这些子接口即可。
有一些接口不想让用户显示知道并使用
显示实现接口
class WarmKiller:IGentleman,IKiller{public void Love(){}void IKiller.Kill(){} //显示实现:此时必须得是IKiller实例才可以使用Kill方法。}
8.2 反射
.NET框架特有
以不变应万变
有时程序需要在 运行时 根据用户需要处理一些逻辑,这些逻辑很难在编写程序时全面地写出来,即使写出来了,程序体也会十分臃肿、难维护。
C#基础知识(停止更新、移步博客园)相关推荐
- 【FastAPI后台API 一】配置文件(移步博客园或个人网站)
FastAPI 配置文件 准备使用Vue + FastAPI开发一套后台管理系统,记录自己使用FastAPI的技术点. 移步博客园 https://www.cnblogs.com/CharmCode/ ...
- [持续更新中]博客园开放api、还有知乎、V2EX开放接口
最新整理,持续更新ing- 博客园开放api 博客服务接口 http://wcf.open.cnblogs.com/blog/help 新闻服务接口 http://wcf.open.cnblogs.c ...
- 【FastAPI 学习十二】定时任务篇 (移步博客园或个人网站 无广告,界面清爽整洁)
声明 目前个人放弃CSDN平台,文章只发布于个人网站和博客园 博客园地址 [FastAPI 学习十二]定时任务篇
- linux基础知识全面总结,51CTO博客-专业IT技术博客创作平台-技术成就梦想
根据RH033课程整理而成. 12月19号 Lecture 10 进程:活体,程序的副本 定义:进程是进程实体的运行过程,是系统进行资源分配和调度的基本单位.--<计算机操作系统> 进程的 ...
- 基于ReactNative实现的博客园手机客户端
注:升级版本请移步:http://www.cnblogs.com/mcmurphy/p/5934993.html 去年九月,facebook发布了react-native,将web端的javaScri ...
- 博客园是个大金矿,管理员不挖掘有些可惜:给博客园提一些双赢的建议
当前十天排行榜里排在首页的文章是,『建议』给博客园官方的一个意见,这说明博客园的广大用户(也包括我)非常乐意看到博客园不断进步. 博客园在国内技术论坛里,应该说是有一定的知名度,每天的流量不少,要知道 ...
- 博客园android,博客园android客户端
博客园app是一个面向开发者的知识分享社区.博客园官方app推动并帮助开发者通过互联网分享知识,让更多开发者从中受益,致力于帮助开发者用代码改变世界. 软件介绍 博客园app是为IT技术人员们提供一个 ...
- TinyKing的博客园
Hi,all 我的博客园地址:http://www.cnblogs.com/tinyking/ 以后博客将更新到博客园 转载于:https://blog.51cto.com/tinyking/1858 ...
- 希望博客园可以开个邮件列表
我到现在都在寻找中文的一个 dotnet 的类似论坛可以问问题有人解答的地方.用过很多的论坛 CSDN 我不是很喜欢,其他的地方人气很少,提问的问题很少有人解答.最近扎根博客园,很喜欢这里的气氛和人气 ...
- 博客园博客美化相关文章目录
本博客所有文章分类的总目录链接:本博客博文总目录-实时更新 1.博客园美化相关文章目录 1.[分享]博客美化(1)基本后台设置与样式设置 2.[分享]博客美化(2)自定义博客样式细节 3.[分享]博 ...
最新文章
- ML:MLOps系列讲解之《CRISP-ML (Q)ML生命周期过程—了解机器学习开发的标准过程模型—业务和数据理解→数据工程(数据准备)→ML模型工程→评估ML模型→模型部署→模型监控和维护》解读
- 嵌入式tomcat例子
- 数字信号处理笔记1-信号与常见操作
- Android之Launcher分析和修改2——Icon修改、界面布局调整、壁纸设置
- oracle 授权 增删改查权限_Oracle增删改查与函数
- Python检测U盘插入、自动复制文件并写入新文件
- SQL笔试之盘古开天
- Linux下JAVA线程占用CPU高的分析方法
- C#文件过滤器filter
- Excel转PDF,Excel行数过多导致PDF折行、换行显示
- 如何解决CPU过热100度自动关机
- 用DEV-C++写一个走迷宫小游戏1.2最终版(完结,撒花)
- R语言中 attach()与detach(),及with()的使用
- 华东理工大学pk华东师范大学计算机专业,华东理工大学朱为宏教授和华东师范大学杨海波教授合作在光控手性金属配位自组装体系的研究中取得突破性进展...
- 大军师司马懿之军师联盟
- windows系统 电脑系统重装详细教程(看这一篇就够了)
- 外国月亮也不圆?在硅谷,只有失败者才朝九晚五
- 【版本管理】软件项目版本号的命名规则及格式
- 【CenterNet】模型文件resnet101-5d3b4d8f.pth下载
- 20201111-jetson nano系统安装+输入法+codeoss+联调舵机