目录
[1. 命名空间声明 Namespace](#1. 命名空间声明 Namespace)
[2. 一个 class 类](#2. 一个 class 类)
[3. class 方法(类方法)](#3. class 方法(类方法))
[4. class 属性](#4. class 属性)
[5. 一个 main 方法(程序入口)](#5. 一个 main 方法(程序入口))
[6. 语句&表达式](#6. 语句&表达式)
[7. 注释](#7. 注释)
[1. 区分大小写](#1. 区分大小写)
[2. 所有语句和表达式必须用分号";"结尾](#2. 所有语句和表达式必须用分号“;”结尾)
[3. 用tab键可获取提示的语句](#3. 用tab键可获取提示的语句)
[4. 注意在打印字串时,若想展示变量数据,记得用{下标}站位符](#4. 注意在打印字串时,若想展示变量数据,记得用{下标}站位符)
[5. 调用方法时,不能直接用类.方法(),而是要先实例化类](#5. 调用方法时,不能直接用类.方法(),而是要先实例化类)
[6. 注释方法](#6. 注释方法)
[1. 程序执行是从Main方法开始的](#1. 程序执行是从Main方法开始的)
[2. Main方法的定义是用static,而不是public](#2. Main方法的定义是用static,而不是public)
[1. 不回传值](#1. 不回传值)
[2. 回传值](#2. 回传值)
[3. Console.WriteLine( )拼接字串和变量值](#3. Console.WriteLine( )拼接字串和变量值)
[(1)用("XXX{下标}XXX", 变量名)](#(1)用("XXX{下标}XXX", 变量名))
[(2)用("XXX{变量名}XXX")](#(2)用("XXX{变量名}XXX"))
[4. 处理字符串](#4. 处理字符串)
[5. 传递参数](#5. 传递参数)
[6. 可回传多个值(按输出传递参数)](#6. 可回传多个值(按输出传递参数))
[7. 数组](#7. 数组)
[8. 多态性](#8. 多态性)
[10. 重载运算符](#10. 重载运算符)
[11. 异常捕捉](#11. 异常捕捉)
[12. 多线程](#12. 多线程)
[13. 静态 static](#13. 静态 static)
[14. 访问修饰符](#14. 访问修饰符)
[① protected的使用](#① protected的使用)
[② internal的使用](#② internal的使用)
[15. 扩展方法](#15. 扩展方法)
[16. 命名空间](#16. 命名空间)
[17. 自定义列表、字典内容](#17. 自定义列表、字典内容)
[1. 可空类型(?)](#1. 可空类型(?))
[2. null合并符(??)](#2. null合并符(??))
[1. ReadKey()](#1. ReadKey())
[2. ReadLine()](#2. ReadLine())
[(六)遇到问题:错误 (作用中) CS8370 在 C# 7.3 中无法使用 '集合运算式' 功能。请使用语言版本 12.0 或更高的版本。](# 7.3 中无法使用 '集合运算式' 功能。请使用语言版本 12.0 或更高的版本。)
[1. 默认格式](#1. 默认格式)
[2. 常用格式](#2. 常用格式)
[3. 时间戳格式](#3. 时间戳格式)
一、程序结构
.NET 是软件框架,可开发程序。 C# 是基于.NET框架的编程语言。
(一)内容
1. 命名空间声明 Namespace
2. 一个 class 类
3. class 方法(类方法)
4. class 属性
5. 一个 main 方法(程序入口)
6. 语句&表达式
7. 注释
(二)举例
cs
using System;
/* 命名空间 HelloWorldApplication */
namespace HelloWorldApplication
{
/* 类名为 HelloWorld */
class HelloWorld
{
/* main函数(程序入口) */
static void Main(string[] args)
{
/* 我的第一个 C# 程序 */
Console.WriteLine("Hello World!");
Console.ReadKey();
}
}
}
二、编写规范
1. 区分大小写
2. 所有语句和表达式必须用分号";"结尾
3. 用tab键可获取提示的语句
4. 注意在打印字串时,若想展示变量数据,记得用{下标}站位符
举例:
cs
Console.WriteLine("sum1={0}", 330);
// 而不是Console.WriteLine("sum1=", 330);
5. 调用方法时,不能直接用类.方法(),而是要先实例化类
若出现问题:
需要有物件参考,才可使用非静态栏位、方法或属性。
解决:
先初始化类对象,然后再使用类里的方法。
6. 注释方法
cs
/// <summary>
/// <para> 这是一个注释内容 </para>
/// </summary>
三、定义
(一)执行程序
1. 程序执行是从Main方法开始的
2. Main方法的定义是用static,而不是public
举例:
cs
static void Main(string[] args){ }
// 而不是public void Main(string[] args){ }
(二)定义方法&变量、传递数据、数据处理
1. 不回传值
设置方法名前的回传类型为void
cs
public void Acceptdata(string args)
{
bookname = args;
}
2. 回传值
设置方法名前的回传类型为回传值的类型
cs
public int Acceptdata()
{
int bookprice = 10;
return bookprice;
}
3. Console.WriteLine( )拼接字串和变量值
(1)用("XXX{下标}XXX", 变量名)
cs
string[] bookinfo = new string[] { "数据结构", "¥20" };
Console.WriteLine("这本书的名字是:{0},价格是{1}", bookinfo[0], bookinfo[1]);
// 这本书的名字是:数据结构,价格是¥20
Console.WriteLine("这本书的价格是:{1},名字是{0}", bookinfo[0], bookinfo[1]);
// 这本书的价格是:¥20,名字是数据结构
(2)用$("XXX{变量名}XXX")
cs
Console.WriteLine($"这本书的价格是:{bookinfo[1]},名字是{bookinfo[0]}");
// 这本书的价格是:¥20,名字是数据结构
4. 处理字符串
(1)字符串是否包含某值
cs
string str1 = "this is a text!";
string str2 = "text";
Console.WriteLine(str1.Contains(str2));
(2)截取字符串的某部分
cs
string str1 = "this is a text!";
string child_str = str1.Substring(3);
Console.WriteLine(child_str);
5. 传递参数
(1)按值传参
实参和形参互不影响。形参发生改变时,不会影响到实参。
举例:
cs
using System;
namespace testapplication
{
class ClsA
{
public void Swapdata(int a, int b)
{
int c = a;
a = b;
b = c;
Console.WriteLine("換值方法內:a={0},b={1}", a, b); // 換值方法內:a=3,b=2
}
static void Main(string[] args)
{
int x = 2;
int y = 3;
ClsA c = new ClsA();
c.Swapdata(x, y);
Console.WriteLine("Main方法內:a={0},b={1}", x, y); // Main方法內:a=2,b=3
Console.ReadKey();
}
}
}
(2)按引用传参
ref关键字声明引用参数。
举例:
cs
using System;
namespace testapplication
{
class ClsA
{
public void Swapdata(ref int a, ref int b)
{
int c = a;
a = b;
b = c;
Console.WriteLine("換值方法內:a={0},b={1}", a, b); // 換值方法內:a=3,b=2
}
static void Main(string[] args)
{
int x = 2;
int y = 3;
ClsA c = new ClsA();
c.Swapdata(ref x, ref y);
Console.WriteLine("Main方法內:a={0},b={1}", x, y); // Main方法內:a=3,b=2
Console.ReadKey();
}
}
}
6. 可回传多个值(按输出传递参数)
因为return只能回传一个值,用out属性可以回传多个。
cs
using System;
namespace testapplication
{
class ClsA
{
public void Rtndata(int m, int n, out int x, out int y)
{
x = m * m;
y = n * n;
}
static void Main()
{
int a = 2;
int b = 3;
ClsA c = new ClsA();
c.Rtndata(a, b, out a, out b);
Console.WriteLine("a={0}, b={1}", a, b);
Console.ReadLine();
}
}
}
7. 数组
(1)初始化数组
举例:(定义+赋值)
cs
// int类型的数组
int[] num_arr = new int[3];
int[] num_arr2 = new int[] {10, 20};
// 字符串类型的数组
string[] bookname = new string[] { "aa", "bb" };
(2)传值时
cs
class ClsA
{
string[] bookname;
public void Bookdata(string[] args)
{
bookname = args;
}
public string[] Rtndata() {
return bookname;
}
}
ClsA c = new ClsA();
c.Bookdata(new string[] {"数据结构", "计算机组成原理" });
(3)访问数组(取值时)
cs
// 第1种:遍历并打印数组中的每个元素
foreach (var item in res)
{
Console.WriteLine(item);
}
// 第2种:用逗号连接数组的每个元素
Console.WriteLine(string.Join(", ", res));
8. 多态性
(1)理解
一个Switch开关按钮,它既可以开,也可以关,在不同的情况下不同的功能作用。
同理,多态性在C#中的实际应用有函数重载。
(2)函数重载
要求函数的定义必须不同。即,传入的参数类型不同or参数个数不同。
举例:
cs
using System;
namespace testapplication
{
class ClsA
{
public int AddData(int a, int b)
{
return a + b;
}
public int AddData(int a, int b, int c)
{
return a + b + c;
}
public int AddData()
{
return 666;
}
}
class ClsB {
static void Main()
{
ClsA a = new ClsA();
int sum1 = a.AddData(1,2);
int sum2 = a.AddData(1, 2,3);
int sum3 = a.AddData();
Console.WriteLine("sum1={0}", sum1);
Console.WriteLine("sum2={0}", sum2);
Console.WriteLine("sum3={0}", sum3);
Console.ReadKey();
}
}
}
9. C#不能多重继承,但可用接口实现多重继承
比如,错误写法:
cs
class ClsA{ }
class ClsB{ }
class ClsC{ }
class ClsAll: ClsA, ClsB, ClsC{ }
正确写法:只能继承一个类,其余的类改成接口
cs
class ClsA { }
interface IClsB{ }
interface IClsC{ }
class ClsAll: ClsA, IClsB, IClsC{ }
完整的正确写法:
cs
using System;
namespace testapplication
{
class ClsA
{
protected int aa;
protected int bb;
public void ChangeVar(int a, int b)
{
aa = a+10;
bb = b+100;
}
}
interface IclsB
{
// 接口
int SubtData();
}
class ClsAll: ClsA, IclsB // 继承最多一个类,可多个接口
{
public void AddCount()
{
Console.WriteLine("add res={0}", aa + bb); // 使用的是基类的aa和bb
}
public int SubtData() // 重写了接口的方法
{
Console.WriteLine("subtract res={0}", bb - aa);
return bb -aa;
}
}
class ClsTest {
static void Main()
{
ClsAll a = new ClsAll();
a.ChangeVar(20,300); // 继承基类的方法
a.AddCount(); // 派生类的方法
a.SubtData(); // 继承接口的方法
Console.ReadKey();
}
}
}
10. 重载运算符
(1)含义
(2)注意
不能用ref和out等参数,只能使用值参数。
有>=操作符,就必须有对称的<=操作符。
(3)举例
cs
using System;
namespace testapplication
{
class clsA
{
private int num1;
private int num2;
public int rtnNum1(){return num1;}
public int rtnNum2(){return num2;}
public void setNum(int a, int b)
{
num1 = a;
num2 = b;
}
public int addFunc()
{
return num1 + num2;
}
public int subtFunc()
{
return num2 - num1;
}
public static clsA operator+ (clsA cls1, clsA cls2)
{
clsA clsa = new clsA ();
clsa.num1 = cls1.num1 + cls1.num1;
clsa.num2 = cls1.num2 + cls1.num2;
return clsa;
}
public static clsA operator- (clsA cls1, clsA cls2)
{
clsA clsa = new clsA ();
clsa.num1 = cls1.num1 - cls2.num1;
clsa.num2 = cls1.num2 - cls2.num2;
return clsa;
}
public static bool operator <=(clsA cls1, clsA cls2)
{
clsA clsa = new clsA();
if (cls1.num1 <= cls2.num1 && cls1.num2 <= cls2.num2)
{
return true;
}
return false;
}
public static bool operator >=(clsA cls1, clsA cls2)
{
clsA clsa = new clsA();
if (cls1.num1 >= cls2.num1 && cls1.num2 >= cls2.num2)
{
return true;
}
return false;
}
}
class clsB
{
static void Main()
{
clsA clsA_1 = new clsA ();
clsA clsA_2 = new clsA ();
clsA clsA_3 = new clsA ();
clsA_1.setNum(2, 20);
clsA_2.setNum(3, 30);
// 测试 一般方法
Console.WriteLine("clsA_1的和: {0}", clsA_1.addFunc()); // 2+20
Console.WriteLine("clsA_2的和: {0}", clsA_2.addFunc()); // 3+30
// 测试 operator重载操作符"-"
clsA_3 = clsA_2 - clsA_1;
Console.WriteLine("clsA_3的和: {0}", clsA_3.addFunc()); // (3-2) + (30-20)
// 测试 operator重载操作符">="
if (clsA_1 <= clsA_2)
{
Console.WriteLine("clsA_1的值1【{0}】小于clsA_2的值1【{1}】,clsA_1的值2【{2}】小于clsA_2的值2【{3}】",
clsA_1.rtnNum1(), clsA_2.rtnNum1(), clsA_1.rtnNum2(), clsA_2.rtnNum2());
}
Console.ReadKey();
}
}
}
11. 异常捕捉
其中,throw ex;表示抛出异常
举例:
cs
using System;
public class Example
{
class Test
{
public void exc(int a, int b)
{
try
{
int test_res = a / b;
Console.WriteLine("this is the code that need to be executed");
}
catch (Exception ex)
{
Console.WriteLine("occur Exception: {0}", ex);
throw ex;
}
finally
{
Console.WriteLine("this is the final code");
}
}
}
public static void Main()
{
Test t = new Test();
t.exc(3, 0);
Console.ReadKey();
}
}
12. 多线程
写法:main函数和线程函数必须写在同一个类中
举例:
cs
using System;
using System.Threading;
public class Example
{
class Test
{
public static void threadFunc()
{
Console.WriteLine("this is a child thread");
}
static void Main()
{
ThreadStart ths = new ThreadStart(threadFunc);
Thread th = new Thread(ths);
Console.WriteLine("this is the main thread");
th.Start();
Console.ReadKey();
}
}
}
13. 静态 static
(1)静态结构
理解:相当于缓存
包括:静态变量、静态方法、静态类
识别:加上static修饰符
(2)静态方法被调用时
只能由类访问(实例方法只能由实例化后的对象访问)
一般适用于该方法被反复调用多次。
(3)静态类的设定前提
一般适用于被经常使用的类型。即,不用每次使用类方法时都先实例化一次。
但很少用的类型,就无需定义为静态类,因为一直占内存,只有等到程序停止或被卸载时才释放内存(如果用实例化的话,可以即时释放内存)。
(4)静态类的特点
不能被实例化;不能被继承;包含的都是静态成员(静态变量、静态方法)。
(5)注意
无论是否是静态,在多次调用同个类(或实例对象)时,变量只会在第一次调用时被初始化,后几次都会沿用上一次最新变量的值。
(6)举例
cs
using System;
namespace testApp
{
static class StaticCls
{
static int booknum = 0;
public static int staticFunc()
{
booknum++;
return booknum;
}
}
class NoStaCls
{
int booknum = 0;
public int nostaFunc()
{
booknum++;
return booknum;
}
}
class MainCls
{
static void Main()
{
int bookA = StaticCls.staticFunc();
int bookB = StaticCls.staticFunc();
Console.WriteLine($"《static》:this is a number of 【A】books: {bookA}");
Console.WriteLine($"《static》:this is a number of 【B】books: {bookB}");
NoStaCls nos1 = new NoStaCls();
int bookANo = nos1.nostaFunc();
int bookBNo = nos1.nostaFunc();
Console.WriteLine($"《no static》:this is a number of 【A】books: {bookANo}");
Console.WriteLine($"《no static》:this is a number of 【B】books: {bookBNo}");
Console.ReadKey();
}
}
}
14. 访问修饰符
(1)private
存取只能是类自己内部。
(2)protected
存取只能是自己本类、自己的子类。
(3)internal
存取只能是同个命名空间中的类(namespace 定义的类自己内部)。
(4)public
存取没有限制。
举例:
① protected的使用
cs
using System;
class BaseTest // 基类
{
public int a = 10;
protected int b = 2;
}
class ChildTest : BaseTest // 派生类继承基类
{
int c;
int d;
static void Main(string[] args)
{
BaseTest basetest = new BaseTest();
ChildTest childtest = new ChildTest();
childtest.c = basetest.a; //a属于public 可直接从 基类 实例化后获取
childtest.d = childtest.b; // b属于protected 限制只能从 派生类 实例化后获取
Console.WriteLine($"c={childtest.c}");
Console.WriteLine($"d={childtest.d}");
Console.ReadKey();
}
}
② internal的使用
cs
using Common;
using System;
namespace Common // 命名空间1
{
internal class CommonCls // 设定 internal
{
public void Saysomething()
{
Console.WriteLine("running success!");
}
}
}
namespace TestWeb // 命名空间2
{
internal class TestA : Common.CommonCls // 继承其他命名空间的internal类,子类也要internal(权限范围不能大于基类)
{
public void TestFunc()
{
CommonCls c = new CommonCls(); // 实例化其他命名空间的基类
c.Saysomething(); // 调用方法
Console.ReadKey();
}
public static void Main(string[] args)
{
TestA t = new TestA();
t.TestFunc();
}
}
}
15. 扩展方法
(1)作用
在现有类中添加方法。
(2)特点
所在类必须声明为 static 。
该方法本身必须声明为 public static 。
该方法的第一个参数必须包含 this ,并且指定该参数类型。
扩展方法的优先级低于同名的类方法。
除非必要,不要滥用扩展方法。
(3)举例
cs
using System;
static class Program // 静态类
{
static void Main(string[] args)
{
int bookdays = 123;
string res1 = bookdays.ToString(); // 默认的方法
string res2 = bookdays.ToString(" valid", " days"); // 扩展方法,必须用对象来调用
Console.WriteLine("default res is 【{0}】, add new res is 【{1}】", res1, res2);
Console.ReadKey();
}
public static string ToString(this int num1, string str1, string str2) // 声明扩展方法
{
// 扩展方法以及所在类,必须是静态的
// 扩展方法的第一个参数必须有this,以及该参数的类型
return num1 + str1 + str2;
}
}
16. 命名空间
调用代码时,若不在同一个命名空间,则使用using 导入需要调用代码所在的命名空间名。
17. 自定义列表、字典内容
(1)定义列表List类型
cs
var datalist = new List<object> { 123, "abcd"};
// 内容是datalist=[123, "abcd"]
(2)定义列表包字典
cs
namespace StartExeSpace
{
class StartExe
{
public void PrtRes(List<Dictionary<string, object>> dt)
{
foreach(var d in dt)
{
Console.WriteLine($"key:【{d["key"]}】, value:【{d["val"]}】");
}
Console.ReadKey();
}
static void Main()
{
// 如果类型不一致,就用object
var datalist = new List<Dictionary<string, object>> //定义列表包字典
{
new Dictionary<string, object> { { "key", "教育" }, { "val", "家" } },
new Dictionary<string, object> { { "key", "科幻" }, { "val", "三体" } },
new Dictionary<string, object> { { "key", "教育" }, { "val", 123 } },
}; // 类似于python的[{"key": "教育", "val": "家" }, {"key": "科幻", "val": "三体" }, {"key": "教育", "val": "数据结构" }]
var se = new StartExe();
se.PrtRes(datalist); //打印展示数据
}
}
}
三、基础使用
(一)当赋值为空时
1. 可空类型(?)
2. null合并符(??)
举例:
cs
using System;
namespace testapplication
{
class ClsA
{
static void Main()
{
// 避免赋值的值类型"null 空",与定义的类型"int"不同,而导致的错误(2种方法)
// 第一种(当a的值赋予null空时,可在int类型后加一个?问号)
int? a = null;
// 第二种(当a的值赋予null空时,可在空值后加2个问号)
int b = a??0;
Console.WriteLine("a={0},b={1}", a,b); // a=null, b=0
Console.ReadKey();
}
}
}
(二)关闭"程序自动退出"
cs
Console.ReadKey();
// 程序会在有任意按键动作后退出。
(三)ReadKey()和ReadLine()区别
1. ReadKey()
是等待按任意键,才执行下一步。
2. ReadLine()
是等待输入内容后 ,需要按回车键,才执行下一步。
(四)Convert转换类型
cs
string str = "123";
int number = Convert.ToInt32(str);
// 转换成功,number为123
(五)获取用户输入
默认用户输入的值是字串,若想输入的值是自定义类型,则需要强制转换。
举例:
cs
string read_str = Console.ReadLine();
int read_int = Convert.ToInt32(Console.ReadLine());
(六)遇到问题:错误 (作用中) CS8370 在 C# 7.3 中无法使用 '集合运算式' 功能。请使用语言版本 12.0 或更高的版本。
解决:先检查是否为语法错误。若不是个人因素,则修改系统设定。即,找到项目下的.csproj格式的文件,然后在<PropertyGroup>中插入<LangVersion>。
cs
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
. . .
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
. . .
<LangVersion>latest</LangVersion>
</PropertyGroup>
(七)处理日期
cs
DateTime dt = new DateTime(2024, 05, 29, 17, 30, 01, 02);
string dt_str1 = dt.ToString("y yy yyy yyyy"); // 24 24 2024 2024
string dt_str2 = dt.ToString("M MM MMM MMMM"); // 5 05 五月 五月
string dt_str3 = dt.ToString("yyyy/MM/dd HH:mm:ss.fff"); // 2024/05/29 17:30:01.002
string dt_str4 = dt.ToString("yyyy/MM/dd tt hh:mm dddd"); // 2024/05/29 下午 05:30 星期三
Console.WriteLine("年的格式:{0}", dt_str1);
Console.WriteLine("月的格式:{0}", dt_str2);
Console.WriteLine("年月日 時間 的格式:{0}", dt_str3);
Console.WriteLine("年月日 時間 周 的格式:{0}", dt_str4);
Console.ReadKey();
(八)当前时间
1. 默认格式
cs
DateTime now = DateTime.Now;
Console.WriteLine($"default:【{now}】");
//default:【2024 / 6 / 11 下午 01:55:31】
2. 常用格式
cs
DateTime now = DateTime.Now;
string nowtime = now.ToString("yyyy-MM-dd HH:mm:ss.fff zzz"); // ss代表两位数的秒钟;fff代表毫秒的三位数;zzz表示时区偏移量
Console.WriteLine($"nowtime:【{nowtime}】");
//nowtime:【2024 - 06 - 11 13:55:31.531 + 08:00】
3. 时间戳格式
(1)真实时间戳
cs
DateTime utcnow =DateTime.UtcNow;
Console.WriteLine($"utcnow:【{utcnow}】");
(2)字符串的时间戳
cs
DateTime now = DateTime.Now;
string tmkey = now.ToString("yyyyMMddHHmmssffff");
Console.WriteLine($"timekey:【{tmkey}】");
//timekey:【202406111355315318】