C#基础复习笔记

目录

一、第一天

1、访问修饰符

2、类

3、命名规则

4、变量在内存中的分布

1、值类型

2、引用类型

二、第二天

1、结构体

2、枚举

3、常用数据类型转换

4、图片资源的运用

(1)本地导入图片

(2)后端加载图片

(3)从资源中加载图片

三、第三天


一、第一天

1、访问修饰符

public>internal>protected>private

  • public:公开的,所有都可以访问
  • internal:内部的,当前项目内可以访问
  • protected:受保护的,只在类的内部及该类的子类可以访问
  • private:私有的,只在类的内部可以访问

2、类

类的成员包含字段(静态、非静态)、属性(静态、非静态)、方法(静态、非静态)、常量等

cs 复制代码
internal class People
{
    
    public string sex;//字段
    public int age;//字段
    public int Height { get; set; }//属性
    public string Name { get; set; }//属性
    private int weight;

    public int Weight             //属性
    {
        get { return weight; }
        set { weight = value; }
    }

    public void Study()          //方法
    {
        MessageBox.Show("正在学习中...");
    }

    public static void Meth2()  //静态方法
    { 
    
    }

    public readonly string position = "地球";  //只读字段
    public static bool alive = true;//静态字段
    public const int VALUE = 1;     //常量
    public static int Value2 { get; set; } //静态属性


}

3、命名规则

字段:Camel(骆驼)命名法:首单词小写,其余每个单词首字母大写

属性、方法:Pascal命名法:每个单词首字母都要大写

常量:每个字母大写

4、变量在内存中的分布

C#中的变量分为两类

1、值类型

值类型变量内存分布在栈上,存储的是值

注意:并不是所有值类型都存储在栈上,当在方法内部定义的局部变量才存在栈上,当作为类的字段存在的值类型,跟着类的实例对象一起存在堆上

cs 复制代码
People people1 = new People();
people1.Name = "张三";
people1.age = 18;
people1.sex = "男";

这些对象的属性,虽然是值类型,但跟着对象存储在堆上

2、引用类型

引用类型的对象分配上堆上,引用类型变量本身分配在栈上,存储的是对象在堆内存上的地址

cs 复制代码
People people1 = new People();
people1.Name = "张三";
people1.age = 18;
people1.sex = "男";

People people2 = new People();
people2.Name = "李四";
people2 = people1;

MessageBox.Show(people2.Name);

people2 = people1; 这句代码会把people1存储的堆内存地址复制给people2,效果如下:

此时,people2与people1指向的是堆上的同一块内存,因此people2.Name 是"张三"

二、第二天

1、结构体

结构体是值类型,内部可以有字段、属性、方法等,与类相似但也有区别

cs 复制代码
// <summary>
    /// 结构体是值类型,存储一般都是一些简单的数据类型,当我们想做一些轻量化的运算操作
    /// </summary>
    struct Teacher
    {
        int age;
        string name;
        public int MyProperty { get; set; }
        public void Meth()
        { 
        
        }
    }

与类的区别:

(1)类要使用必须通过new关键字实例化,结构体可new也可直接使用

(2)类是引用类型存储在堆上,结构体是值类型存储在栈上

对结构体中的数据赋值就理解成对普通数据类型的赋值操作,都是在栈内存中

(3)类的赋值,是把堆内存地址复制过去,结构体只是把值内容复制过去

cs 复制代码
Teacher teacher1 = new Teacher();
teacher1.age = 20;
teacher1.name = "李四";

Teacher teacher2;
teacher2 = teacher1;
teacher1.name = "赵六";
MessageBox.Show(teacher2.name);

teacher2 = teacher1 ;这句代码会把teacher1在栈上的值复制给teacher2,然后再改变teacher1在栈上的值,与teacher2无关

(4)类中可以有构造器,结构体中不能有构造器

(5)类可以继承类,结构体不允许继承类但可实现接口

cs 复制代码
struct Teacher:ISleep
{
    public int age;
    public string name;
    public int MyProperty { get; set; }
    public void Meth()
    { 
    
    }
   
}
interface ISleep
{ 

}

2、枚举

与类、结构体、接口等是同一级别

(1)枚举的定义

cs 复制代码
namespace ClassLearn
{
    internal enum MyDirection
    {
        Left = 2,
        Top = 4,
        Right = 8,
        Bottom = 100
    }
}

(2)枚举的使用

cs 复制代码
internal class People
{
    public MyDirection Dir { get; set; }
}
cs 复制代码
People people1 = new People();
people1.Dir = MyDirection.Left;

MessageBox.Show(people1.Dir.ToString());

int a = (int)people1.Dir;//把枚举类型转换成对应的值
MessageBox.Show(a.ToString());


Type t = typeof(MyDirection);//获取类型方法1
Type t2 = Type.GetType("ClassLearn.MyDirection");//获取类型方法2
Type t3 = people1.Dir.GetType();//获取类型方法3

string s = Enum.GetName(t3, 100);//通过值拿到枚举对应的字符串
MessageBox.Show(s);

MyDirection b  = (MyDirection)Enum.Parse(t3, "Left");//通过字符串拿到对应的枚举类型
if(b == MyDirection.Left)
    MessageBox.Show("true");

运行结果:

3、常用数据类型转换

4、图片资源的运用

(1)本地导入图片

缺点:图片会嵌入exe文件中, Debug中的.exe文件会随着图片越多,越来越大

当0张图片时:

当1张图片时:

当2张图片时:

(2)后端加载图片

cs 复制代码
//方式1:绝对路径
pictureBox1.Image = Image.FromFile("D:\\Projects\\Python学习\\CSharpLearn\\ClassLearn\\bin\\Debug\\beautiful.jpg");
//方式2:
string imagePath = AppDomain.CurrentDomain.BaseDirectory + "beautiful.jpg";
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "beautiful.jpg");
pictureBox1.Image = Image.FromFile(path);

pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;

(3)从资源中加载图片

cs 复制代码
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox3.SizeMode = PictureBoxSizeMode.StretchImage;

pictureBox1.Image = Resources.microsoft;
pictureBox2.Image = Resources.登录图标;
pictureBox3.Image = Resources.exit;

运行效果:

已知图片名称,如何在资源文件中提取图片?

cs 复制代码
ResourceManager resourceManager = new ResourceManager("ClassLearn.Properties.Resources", Assembly.GetExecutingAssembly());
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.Image = (System.Drawing.Image)resourceManager.GetObject("microsoft");

运行效果:

5、扩展方法

既然类里面已经可以定义方法了,为什么还要多此一举发明"扩展方法(Extension Methods")?

本质上,这是为了在不修改原有代码 的前提下,实现功能的无限延伸

我们可以从以下几个核心场景来理解它的必要性:

1. 拯救"无法修改"的类(最核心原因)

在开发中,你经常会遇到以下情况:

  • 系统内置类 :比如 stringintDateTimeList<T>。这些类是微软写在 .NET 底层框架里的,你根本没有权限去修改它们的源码。
  • 第三方库:你引用的别人写的 DLL 文件,同样无法修改。

如果你突然觉得 string 类缺少一个"判断是否为手机号"的方法,你没法去 string 类里加代码。这时候,扩展方法就成了救星,它允许你像调用原生方法一样,给这些"封闭"的类增加自定义功能。

2. 保持代码的"链式调用"与可读性

假设你要给 string 加一个"去除所有空格"的功能。

  • 不用扩展方法 :你只能写一个静态工具类 StringHelper.RemoveSpaces(myString)。当多个操作连在一起时,代码会变成这样,非常难读:
    StringHelper.Trim(StringHelper.RemoveSpaces(StringHelper.ToLower(myString)))
  • 使用扩展方法 :你可以像这样优雅地链式调用:
    myString.ToLower().RemoveSpaces().Trim()
    这种写法不仅符合人类的阅读习惯,而且极大地提升了代码的整洁度。

3. 遵循"开闭原则"(OCP)

面向对象设计有一个重要原则:对扩展开放,对修改封闭

如果一个类已经写好了,并且有很多地方都在用它,你直接去修改这个类的源码(加个方法),可能会不小心引入 Bug,影响所有调用它的地方。扩展方法允许你在外部安全地增加功能,完全不用动原来的类。

4. 为"接口"提供默认实现

在 C# 8.0 之前,接口(Interface)里是不能写方法体的,只能定义签名。如果你想给所有实现了 IEnumerable 接口的集合(如 List, Array)统一增加一个功能,你没法在接口里写代码。

通过扩展方法,你可以针对"接口"进行扩展。只要一个类实现了这个接口,它就自动拥有了这个扩展方法。LINQ 就是利用这个机制,给所有的集合加上了 Where, Select, OrderBy 等海量功能。

核心语法规则:

  1. 必须写在**静态类(static class)**中。
  2. 方法必须是静态方法(static) ,且第一个参数必须加上 this 关键字(代表你要扩展的那个对象)。

原有People类

cs 复制代码
internal class People
{
    public MyDirection Dir { get; set; }
    
}

扩展类

cs 复制代码
//1、必须是静态类
internal static class PeopleExtension
{
    //2、必须是静态方法,第一个参数带this
    public static void Study(this People people)
    {
        MessageBox.Show("People在学习...");
    }
}

扩展方法的使用

虽然扩展类里面写的是静态方法,但实际上扩展的是类的对象的方法

因为扩展方法的第一个参数加了 this ,这就意味着这个方法必须绑定到一个具体的对象实例上才能调用

而类的静态方法不能扩展,只能写静态工具类来增加静态方法

cs 复制代码
People people = new People();
people.Study();

运行效果:

当然,一个扩展类里可以为多种类做扩展方法

三、第三天

1、var、object、dynamic区别

(1)object

定义的数据类型可以改变

cs 复制代码
//object定义的数据类型可以改变
object f = new People();
f = 1;
f = "Hello World";
f = 2.5f;

但缺点是涉及到装箱、拆箱,性能下降

装箱: 将值类型(隐式)转换成引用类型,会在托管堆上为对象分配内存

**拆箱:**将引用类型(显式)强制转换成值类型

cs 复制代码
//装箱:将值类型(隐式)转换成引用类型,会在托管堆上为对象分配内存
int val = 100;
object f = val;

//拆箱:将引用类型(显式)强制转换成值类型
int b = (int)f;

(2)var关键字

只能放在方法里作为局部变量使用

var定义好的数据类型不能改变,var定义的变量是在编译环境下检测数据类型

var方便编译器自动检测数据类型,不需要我们考虑

cs 复制代码
 List<People> list = new List<People>();
 var g = list.Where(x=>x.Age == 100).ToList().FirstOrDefault();
 var p = list.Where(x => x.Age == 100).ToArray();

(3)dynamic

dynamic是程序运行过程中才识别数据实际类型

dynamic定义的变量在运行过程中可以改变数据类型

|---------|-----------|----------------|
| 关键字 | 能否定义成全局变量 | 定义好的变量能否改变数据类型 |
| object | √ | √ |
| var | × | × |
| dynamic | √ | √ |
[object/var/dynamic的区别]

2、委托

3、事件

4、泛型

相关推荐
可靠的仙人掌1 小时前
SAC(Soft Actor-Critic)算法底座
开发语言·算法·php
得闲喝茶1 小时前
跨表数据匹配——VLOOKUP、XLOOKUP
大数据·数据库·笔记·信息可视化·数据分析·excel
学逆向的2 小时前
汇编——数据存储模式
开发语言·汇编·网络安全
geovindu2 小时前
CSharp: Prototype Pattern
开发语言·后端·设计模式·.net·原型模式·创建型模式
天天进步20153 小时前
Python全栈项目--校园食堂点餐与推荐系统
开发语言·python
aaPIXa6223 小时前
C++模板元编程:编译期计算Fibonacci数列
java·开发语言·c++
智慧景区与市集主理人3 小时前
巨有科技:市集笔记内容分发,低成本打造本地流量曝光矩阵
大数据·笔记·科技
eybk3 小时前
写一个可以编制pdf文件的python程序
开发语言·python·pdf
cui_ruicheng3 小时前
Python从入门到实战(八):封装、多态与抽象类
开发语言·python