C#.Net筑基-基础知识
01、C#基础概念
1.1、C#简介
C# (读作C Sharp)是由微软公司开发的一种面向对象、类型安全、高效且简单的编程语言,最初于 2000 年发布,并随后成为 .NET 框架的一部分。所以学习C#语言的同时,也是需要同步学习.NET框架的,不过要要注意C#与.NET的对应版本。
C#语言和Java类似,是一门简单易用、应用广泛的高级编程语言。结合了面向对象编程、事件驱动、泛型编程、异步编程等众多现代化编程概念,属于编译性语言。主要特点:
- 面向对象:封装(类与对象)、继承(类继承、接口继承)、多态等(类继承、多接口继承实现)。
- 类型安全:强类型安全,在编译时检测,提高代码可靠性。
- 交互性,易于各种语言交互,如VB、F#、C++、JavaScript、Python等。
- GC管理:自动内存管理,C# 采用垃圾回收机制,无需申请、释放内存,减少内存泄漏风险。
- 开源跨平台:.NETCore框架是开源跨平台的,支持多种操作系统。
- 强大的标准库,C#拥有丰富的标准类库(.NET Framework或.NET Core),内置各种功能和工具。
- 宇宙第一开发IDE: Visual Studio 提供了强大的开发、调试和设计工具。
.NET Framework最高支持C#语法版本是C#7.3
、.NET Standard 2.1
,可以基于该版本学习,后面的版本可以根据需要学习新增特性即可。
图来源:C#.NET体系图文概述
1.2、开发环境
- 运行环境:安装.NET SDK:下载 .NET, 下载.NET Framework
- 开发环境:开发IDE工具安装Visual Studio ,内置很多开发套件,及多个版本的SDK。
推荐安装
Enterprise
企业版!功能最全。开发工具了解:《Visual Studio工具使用入门》
1.3、Hello World
using System; //引用using
namespace ConsoleApp_Net48 //申明命名空间
{
internal class Program //定义类
{
static void Main(string[] args) //方法,控制台入口函数
{
Console.WriteLine("Hello World!"); //控制台打印输出
Console.ReadLine();
}
}
}
- using 引用命名空间资源。
- namespace 命名空间 :一组代码资源(类、结构、枚举、委托等)的集合。
- class 类:定义一个类,C#中最常用的代码组织单元。
- 方法:特定功能的代码块,有输入和输出(也可为空)。
02、基础语法
C#代码以行为单位,(半角)分号;
结尾,花括号{ 代码块 }
为一个独立的代码区域。
2.1、变量申明
变量类型 变量名 = 值
,变量就是对象值的名字,就像人的名字一样,通过变量来访问具体的对象值。变量可以是局部变量、参数、字段、数组、对象实例、委托等。
- 申明变量、赋值可以一次性,也可分开,也可以一次性申明多个变量。
- 变量的使用前必须初始化(赋值),使用未赋值的变量会引发异常。
- 同一作用域内,一个变量名只能申明一次,不可重复。
- 字符串用
“双引号”
,单个字符用'单引号'
。
也可以用
var
申明,编译器通过值类型推断其具体变量类型,因此申明时必须赋值,var是一个语法糖。
int age; //先申明,后赋值
age = 12;
float weight = 55.55f;
double height = 188.88d; //末尾可以不用带d,默认就是double
var name = "sam";
var lastName = 'T';
string f1, f2, f3 = "F3"; //申明了3个变量,对f3赋值了
var user = new User(); //创建一个User对象实例
User user2 = new User(); //创建一个User对象实例
2.2、代码风格
C#代码的命名风格大多为驼峰命名为主,相对比较统一,不像前端那么麻烦,HTML、CSS、JS、URL各不相同。
- 区分大小写,字母、数字、下划线组成,不能数字开头,不能是关键字。C#中的关键字还是挺多的,参考 C# 关键字。
- 驼峰命名:
- 文件名、类名、接口、方法等都是大驼峰:
UserName
。 - 局部变量为小驼峰:
userName
。 - 字段:下划线+小驼峰/大驼峰都可以
_userName
、_UserName
,或者"m_
"开头,按照团队规范即可。 - 常量:全大写(下划线分割),或者大驼峰都可以,
USER_NAME
、UserName
。
- 文件名、类名、接口、方法等都是大驼峰:
public string UserName { get => _UserName; set => UserName = value; }
public string _UserName;
public const int Max=100;
public static int MaxAge =100;
private static int _MinAge = 20;
public void Sum(int a, int b)
{
int sum = a + b;
}
2.3、注释://
- 单行注释:
//
开头。 - 多行注释:
/*
多行注释*/
(同css) - XML注释:
///
用于类型定义、方法、属性、字段等成员的XML注释,参考:《C#文档XML注释》
/// <summary>
/// XML注释,计算和
/// </summary>
public void Sum(int a, int b)
{
//单行注释
int sum = a + b;
/*
多行注释
输出结果
*/
Console.WriteLine(sum);
}
2.4、作用域
变量的作用域就是指变量的有效范围,C#中的作用域可以简单理解为 花括号{ 代码块 }
的范围,可以是类、方法、控制逻辑(for、while等),或者就一个单纯的{}
。
- 一个花括号
{}
内代码为一个独立的代码区域,有独立的作用域,变量在该作用域内有效。 - 花括号
{}
作用域可以多级嵌套,比如类中包含方法,方法内包括控制逻辑,子作用域可以访问父级的变量(字段、属性、方法、具备变量)。简单理解就是:子级可以访问父级的成员。
private int x = 1; //类字段
void Main()
{
var y = 1 + x; //私有变量
if (y > 0)
{
int z = x + y + 1; //可以访问父级成员
Console.WriteLine(z);
{
int w = x+y+z+1; //可以访问父级成员,及父级的父级
Console.WriteLine(w);
}
}
}
一般情况下,变量的作用域是由代码的词法环境(就是编写代码的位置)来决定的,这比较容易理解。例外情况就是C#中的闭包,常见于动态函数、委托。
03、申明语句
申明变量 | 说明 |
---|---|
Type v | 申明指定类型的变量,int x ,List<int> list |
var | 隐式匿名类型var ,用var 申明变量,编译器根据值推断出类型变量,因此要求必须赋初始值。 |
const | 申明一个常量,申明时必须赋初始值,且不可修改 |
ref | reference 变量是引用另一个变量(称为引用)的变量,可以看做是其别名(分身) |
void Main()
{
int x =100;
List<int> list = new List<int>();
List<int> list2 = new(); //前面已知了类型,后面可省略
int[] arr = [1,2,3]; //C#12的集合表达式,方便的创建数组、集合
List<int> arr2 = [1,2,3];
var n = 1; //匿名类型,自动推断类型
var list3 = new List<int>;
ref int n2 = ref n; //ref另一个变量的别名,n2、n实际指向同一个值,是等效的
const int max =100; //常量
var (name,age) = ("sam",18); //多个变量一起申明、赋值,这只是一种简化的语法糖
(x, n) = (n, x); //还可以用该语法交换变量值,非常优雅
}
3.1、const常量
const 常量,顾名思义就是值永远不会改变的“变量”,可用于局部变量、字段。比如Math.PI
,Int.MaxValue
,用于一些已知的、不会改变的值。
- 申明常量的同时必须赋初始化值,不可修改,在编译时值会内联到代码中。
- 常量只能用于C#内置的值类型、枚举,及字符串。
- 常量值支持表达式,不过仅限于简单的运算,要能在编译时计算出确定的值。
- 枚举其实也是常量。
- 当用定义
const
字段时,该常量字段就和静态字段一样,属于类本身,直接使用。
const double r = 5.0;
const double rs = 2 * Pi * r;
要注意常量(包括枚举)在编译时是把值内联到IL代码中的,因此如果跨程序集引用时,必须一起更新,否则就会出Bug。
3.2、ref 引用(别名/分身)
ref 关键字的核心点就是引用另一个变量的地址,可看做是其别名(分身),指向同一地址。作用和指针操作比较相似,int* y = &x;
,不过ref
更安全、更方便。
具体在使用上有以下一些场景:
使用场景 | 说明 |
---|---|
引用传递参数 | 方法调用时传递引用参数,方法内可修改参数值 ,Foo(ref int number) |
ref return | 返回一个ref 变量,public ref int Foo(ref int n){return ref n;} |
ref 变量 | 引用另一个局部变量,ref int y = ref x |
ref 条件表达式 | ref 用在三元表达式条件? ref (true):ref (fasle) 中,返回引用 |
ref struct | 让struct 完全分配在栈上、不能装箱,只能用于局部变量、参数,一些高性能的场景 |
int x = 1;
ref int y = ref x; //x、y其实同一个变量
Console.WriteLine($"{x},{y}"); //1,1
x++;
Console.WriteLine($"{x},{y}"); //2,2
y++;
Console.WriteLine($"{x},{y}"); //3,3
//换个数组
int[] arr = new int[] { 0, 1, 2};
ref int a = ref arr[0];
a=100;
Console.WriteLine(arr); //100 1 2
ref readonly
:所指向的变量不能修改值,但可以用ref
重新分配一个reference
变量。ref
返回值:用于一个方法的返回值,返回一个变量的引用(别名)
void Main()
{
var arr = new int[] { 1, 2, 3 };
ref int f = ref GetFirst(arr);
f = 100;
Console.WriteLine(arr); //100 2 3
}
private ref int GetFirst(int[] arr)
{
return ref arr[0];
}
在某些场景使用
ref
可以避免值类型在传递时的拷贝操作,从而提高性能,不过不同场景不同,需要具体分析、经过性能测试再确定。
04、常用(控制)语句
语句 | 说明 |
---|---|
if |
条件语句,if(true){ 执行 } |
if ...else |
条件语句,if(true){} else(){} |
if ...else if ...else |
同上,中间可以接多个else if ,不过这个时候一般建议重构下,比如用你switch 模式匹配 |
switch ...case |
根据条件处理多个分支:switch (条件){ case }。case 命中后,注意break 结束,否则会继续执行 |
while (true){} |
循环:条件为true就会循环执行 |
do while (true) |
循环:先执行后判断条件 |
for 循环 |
循环:for 条件循环,支持多个语句逗号隔开。for(int i =0; i<max; i++) |
foreach in |
循环元素:foreeach(int item in items) ,实现了IEnumerable,或有无参数 GetEnumerator() |
await foreach |
foreach 的 异步版本 |
List.ForEach () |
List<T> 自带的循环执行方法,list.ForEach(s=> s.Dump()); |
break |
跳出循环语句,for、foreach、while、switch、do。跳出最近的语句块,如果多层嵌套只会对最近的有效 |
continue |
继续下一次循环,只是后面的代码不执行了,应用条件同break |
return |
结束方法/函数并返回结果(若有),注意是针对函数的。 |
goto |
跳转语句到指定标签,单独标签或者case 值,一般不建议使用,goto 可读性不太好 |
throw |
抛出异常,不再执行后面的代码 |
try.catch.finally |
异常处理,throw 抛出一个异常 |
checked、unchecked | 对整数运算语句进行溢出检查、不检查,如果检查溢出会抛出OverflowException |
fixed | 申明指针固定一个可移动(回收)变量,防止被GC回收,在unsafe 代码中运行 |
stackalloc | 在堆栈上分配内存,int* ptr = stackalloc int[10] |
lock | 互斥锁 Monitor 的语法糖,保障同时只有一个线程访问共享资源 lock(obj){ } |
using | 引用命名空间,释放IDisposable , |
yield | 用于迭代器中返回一个迭代值yield return value ,或表示迭代结束yield break 。 |
4.1、try-catch异常处理
一个标准的异常处理流程:
- try:功能代码,需要捕获异常的地方。
- catch:捕获异常,处理异常。支持多个
catch
语句,捕获不同的异常,多个catch
按照顺序执行。catch
后面可以用when
表达式添加更多筛选条件。 - finally:最后执行的代码,无论是否有异常发生都会执行,多用于最后的清理工作。
- throw:可以抛出一个新的异常,也可以在
catch
直接throw;
,保留原始堆栈信息。
try
{
//功能代码
throw new ArgumentException("参数name为null");
}
//用when添加更详细的筛选条件
catch (ArgumentException e) when (e.InnerException ==null)
{
//处理异常,如记录日志
}
catch (Exception e)
{
//处理异常
throw; //直接throw,保留原始堆栈信息
}
finally
{
//最后执行的代码,无论是否有异常发生都会执行,多用于最后的清理工作
}
异步(线程)中的异常一般不会抛出到调用线程(或主线程),只会在
await
,或获取Task.Result
时才会被抛出来,更多可查看异步编程相关章节。
4.2、using 的5种用法
using 在C#中有很多中用途,常用来引用命名空间、简化释放资源。
using 用途 | 说明 |
---|---|
using namespace | 引用命名空间,比较常用,基本每个类都会使用。 |
global using | 项目全局引用,避免每个类都重复using 相同的命名空间。 |
using 别名 | 用using 来创建命名空间或类型的别名,简化代码中的使用。 |
using static | 引入一个类型的静态成员、嵌套类型,代码中直接使用引入的静态成员。 |
using 语句 | using 语句可确保正确使用 IDisposable 实例,using(var r){} ,简化后无需括号 |
命名空间 namespace 用于组织代码(作用域)的主要方式,用关键字
namespace
来命名,可嵌套。C#10 中可以用文件范围命名空间,减少一层括号嵌套。
global using
的最佳实现是一般创建一个公共的类文件“Usings.cs
”,专门放置项目中全局的公共using
。- 用
using
来创建命名空间别名,使用时需要用到操作符::
来访问下级。 using
可创建任意类型的别名,包括数组、泛型、元祖、指针。
global using System.Text; //全局引用命名空间
using System.Text; //引用命名空间
using json = System.Text.Json.JsonSerializer; //类型别名
using NumberList = double[]; //类型别名:数组
using Point = (int X, int Y); //类型别名:元祖ValueTuple<int, int>
using jsons = System.Text.Json; //空间别名
//namespace myspace; 效果同下,简化写法,可节省一对大括号
namespace myspace
{
public class Program
{
void Main()
{
json.Serialize(new Object());
jsons::JsonSerializer.Serialize(new Object()); //这用到操作符::
NumberList arr = [1,2,3];
}
}
}
从
.Net
6开始,C#项目会根据项目类型隐式包含一些using
引用,比如System
、System.Text
。
using static
,引入一个类型的静态成员、嵌套类型,代码中直接使用引入的静态方法。
using static System.Math;
void Main()
{
var a = Abs(-2 * PI ); //直接使用Math下的静态成员
}
using 语句确保对象在using
语句结束时被释放(调用Dispose
)。也可以直接用using
申明变量,不用大括号{}
,这是一种简化的写法,会在作用域(方法、语句块)结束时释放。
using (StreamReader reader = File.OpenText("numbers.txt"))
{
Console.WriteLine("do read...");
}
// 简化写法,效果和上面一样,直接用using修饰 变量申明
using StreamReader reader2 = File.OpenText("numbers.txt");
//编译后的代码:
StreamReader reader = File.OpenText ("numbers.txt");
try
{
Console.WriteLine ("do read...");
}
finally
{
if (reader != null)
{
((IDisposable)reader).Dispose ();
}
}
using
语句是一种语法糖,会自动生成try...finally
代码。
参考资料
- C#DotNet资料导航
- C#.NET体系图文概述—2024总结
- C# 语言文档
- 《C#8.0 In a Nutshell》
️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀
C#.Net筑基-基础知识的更多相关文章
- CSS基础知识筑基
01.CSS 简介 CSS 指层叠样式表 (Cascading Style Sheets),对HTML网页内容进行统一外观样式设计和管理,给网页进行各种装饰,让她变得美观,是HTML的化妆师.(Cas ...
- JavaScript入门①-基础知识筑基
01.JavaScript基础知识 JavaScript(缩写:JS)是一种具有面向对象能力的.解释型的程序语言,基于对象和事件驱动,具有相对安全性的客户端脚本语言.JavaScript是一门完备的 ...
- .NET面试题系列[1] - .NET框架基础知识(1)
很明显,CLS是CTS的一个子集,而且是最小的子集. - 张子阳 .NET框架基础知识(1) 参考资料: http://www.tracefact.net/CLR-and-Framework/DotN ...
- RabbitMQ基础知识
RabbitMQ基础知识 一.背景 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然 ...
- Java基础知识(壹)
写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...
- selenium自动化基础知识
什么是自动化测试? 自动化测试分为:功能自动化和性能自动化 功能自动化即使用计算机通过编码的方式来替代手工测试,完成一些重复性比较高的测试,解放测试人员的测试压力.同时,如果系统有不份模块更改后,只要 ...
- [SQL] SQL 基础知识梳理(一)- 数据库与 SQL
SQL 基础知识梳理(一)- 数据库与 SQL [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902856.html 目录 What's 数据库 ...
- [SQL] SQL 基础知识梳理(二) - 查询基础
SQL 基础知识梳理(二) - 查询基础 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5904824.html 序 这是<SQL 基础知识梳理( ...
- [SQL] SQL 基础知识梳理(三) - 聚合和排序
SQL 基础知识梳理(三) - 聚合和排序 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5926689.html 序 这是<SQL 基础知识梳理 ...
- [SQL] SQL 基础知识梳理(四) - 数据更新
SQL 基础知识梳理(四) - 数据更新 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5929786.html 序 这是<SQL 基础知识梳理( ...
随机推荐
- Kingbase Create Type 语句使用
Kingbase create type类型创建语句 说明: KingbaseES 数据库中,可以通过CREATE TYPE语句定义一种新的数据类型. 有八种形式的CREATE TYPE.它们分别创建 ...
- UE4接口
官方链接 目的 不同Actor对象具有同一个功能,比如角色按F键可以实现开门,开车,与NPC沟通等操作.其本质就是让所有的Actor对象除了继承UObject以外,再继承这个接口类. 接口的声明 宏的 ...
- CDA数据分析师证书一级Level 1 专业备考资料
CDA数据分析师一级Level 1 专业备考资料 包含视频课程+视频配套参考资料,新版大纲,可以边看边学边做笔记. 考试大纲+模拟题+报考指南 + 教材电子书PDF版 关注订阅号[靠谱杨阅读人生]回复 ...
- SQL日期操作函数(CONCAT、DATE_FORMAT、LAST_DAY)
获取某月底日期:SELECT LAST_DAY('2021-07-01') AS month_end_date; 拼接年月格式: CONCAT(DATE_FORMAT(hp.planned_payme ...
- Python数据类型---列表、元祖、字典【详解】
一.列表(List) 1.列表可以用来存储不同的数据类型,使用 [ ] e.g. 1 service = ['http','ssh','ftp'] 2.列表是有索引的,也就是可以通过下标来访问数据 3 ...
- Agent内存马分析
什么是Java Agent 我们知道Java是一种强类型语言,在运行之前必须将其编译成.class字节码,然后再交给JVM处理运行.Java Agent就是一种能在不影响正常编译的前提下,修改Java ...
- centos部署Django三:编写相关配置文件及启动服务
1. 进入到项目的根目录,编写 uwsgi.xml 配置文件 *:centos用的不是 uwsgi.ini,而是 uwsgi.xml <uwsgi> <socket>127.0 ...
- django项目部署到centos
服务器是使用的阿里云的centos 7.6 项目使用的是 Python3.9.5 + Django 3.2.4 目标:将django项目部署到centos上,centos + Python + dja ...
- 标签栏切换效果 JS
标签栏切换效果 JS 要求:class为tab-box的元素用于实现标签栏的外边框,,分别实现标签栏的标签部分和内容部分. html <div class="tab-box" ...
- .NET周刊【4月第1期 2024-04-07】
国内文章 一个程序员的编年史 https://www.cnblogs.com/lunacy/p/18117213 作者拥有15年软件开发经验,曾在多家公司工作,项目和团队起伏充满变数.2007年,在太 ...