c#笔记-定义类

这篇具有很好参考价值的文章主要介绍了c#笔记-定义类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

声明类

类使用class关键字定义,并且必须在所有顶级语句之下
类的成员只能有声明语句,他们可以使用执行语句赋值初始值。
但不能在脱离声明语句的情况下单独使用执行语句。

class C1
{
    string s = Console.ReadLine();//声明一个变量
    Console.ReadLine();//不跟随声明语句单独使用执行语句
}

字段

直属于类下的东西称为类成员。字段是指成员变量

方法中的变量称为局部变量,在方法执行结束的时候就会清除。
而类成员只有等到整个类实例都没人用了才能一起清除。
没有办法单独判断哪一个成员是以后不会再用的。

字段可以在声明时赋值。但不能使用其他实例成员参与表达式。

class Person
{
    string name = "Alice"; // 可以赋予常量值
    int age = GetAge(); // 错误,不能使用实例方法参与赋值
    double height = weight * 0.9; // 错误,不能使用其他实例字段参与赋值
    double weight; // 可以不赋值

    int GetAge()
    {
        return 12;
    }
}

只读

字段可以使用readonly修饰。在完成实例构造以后就不能再重新赋值了。

class Sudent
{
	public readonly int Age = 60;
	public readonly string Name = "小明";
}

方法

c#不严格区分函数和方法的概念。但在其他语言中,一些定义为成员函数才能叫方法。
参照这个定义,局部函数不认为是方法。

重载

成员方法可以重载。重载是指方法的名字一样。
因为方法的调用需要联合参数一起调用。
所以只要参数列表(指参数的数量,类型,顺序)不同,就仍然能做出区分。

引用参数和基本类型的参数不一样,可以重载。
但他们之间都是相同的引用参数,不能只有in,out,ref不同的情况下重载。

class Printer
{
    public void Print(int number)
    {
        Console.WriteLine($"这个数字是 {number}。");
    }

    public void Print(string message)
    {
        Console.WriteLine($"这个信息是 {message}。");
    }
    
    public void Print(ref string message)
    {
        Console.WriteLine($"这个信息是 {message}。");
    }

    public void Print(double value, string unit)
    {
        Console.WriteLine($"这个数值是 {value} {unit}。");
    }
}

在调用方法时,编译器会查找更为具体的方法。

  1. 如果调用方法的参数列表有一个直接匹配的重载,那么会忽略掉不定参数的重载。
  2. 检查所有参数的隐式转换和自身,如果方法重载有参数更为具体(int)的参数,则忽略掉更抽象的(object)重载。
  3. in参数不需要在调用时添加in,但如果用in引用参数和普通参数重载,则根据调用时是否有in决定重载。
  4. 如果没有或有多个这样的匹配方法,则会报错。

例如Add( 40 , 40)对于以下两个方法会发生歧义。

class Calculator
{
    public void Add(int x, object y)
    {
    //内容略
    }

    public void Add(object x, int y)
    {
    //内容略
    }
}

属性

属性是方法和字段的结合体。
结合方式,在编译后的执行是以方法的形式执行。
在编写源码时以变量的语法来书写。
说白了就是简化方法的调用,把调用方法变得跟直接访问变量似的。

class Damage
{
    int value;

    int Value
    {
        get
        {
            return Math.Max(0, value);
        }
        set
        {
            value = Math.Max(0, value);
            //经典问题,伤害如果是负数会不会给对方回血。
            //属性可以用来校验得到的值进行过滤,来保证获得的值是合法的。
        }
    }

    void Invok()
    {
        Console.WriteLine(Value);
        Value += 10;//访问属性就像访问变量一样
    }
}

get访问器

一个属性至少需要有一个访问器。
在把属性当作变量用的时候,对其进行取值会执行他的get访问器。
如果没有get访问器,那么这个属性就不允许执行取值操作。

get访问器是一个无参的,返回值为属性类型的方法。

set访问器

在把属性当作变量用的时候,对其进行赋值会执行他的set访问器。
没有set访问器的属性是不允许进行赋值操作的。

set访问器是一个有参数,无返回值的方法。
这个参数通过关键字value访问,值为当作变量赋值时用于赋值的值。

init访问器

init访问器用于替代set访问器。类似于只读的字段。
init访问器只允许在构造期间使用。

class Hp
{
    int now;
    readonly int max;
    int Now
    {
        get
        {
            return now;
        }
    }
    int Max
    {
        get
        {
            return max;
        }
        init
        {
            max = value;
        }
    }
}

lamda表达式

如果方法的主体只有一条语句。那么可以用=>连接这条语句,并省略大括号和return
这对访问器同样有效。并且如果只有get访问器,还能省略get和属性的大括号。

但是,通常只给访问器使用。因为访问器外部有一对属性的大括号。即便省略大括号也仍然显眼。

class Mp
{
    int now;
    readonly int max;
    int Now => now;
    int Max
    {
        get => max;
        init => max = value;
    }
}

自动属性

如果一个属性至少具有get访问器。那么他的所有访问器都可以不设置逻辑。

class Student
{
   string Name { get; set; } = "张三";

   int Age { get; init; }

   string Password { get; } = "password";//至少要有get属性
}

这种情况下,可以对自动属性进行赋值。
而编译器会自动生成字段,以及对应的访问器逻辑。对属性的赋值也会转移到对字段的赋值。

生成的字段名字不符合c#的规范,但在编译后的文件里是合法的。
在c#中,这样的字段称为匿名字段。我们无法通过名字访问。

属性和方法的区别

属性和方法的区别在于,调用一个方法是可以单独作为一个操作语句的。
但是属性不能单独放置,他仍然会被视作不执行操作的语句。

所以,何时使用属性,何时使用方法,这个问题也有了一个参考标准。
方法可以单独防止,意味着他会做某些事情,会改变什么东西。
而属性只用来获取值,和对自己控制的那个字段进行赋值,不会产生其他影响。

索引器

索引器的名字必须是this。他的参数使用[]而不是(),且必须有至少一个参数。

class StringCollection
{
    string[] arr = new string[100];

    string this[int i]
    {
        get => arr[i];
        set => arr[i] = value;
    }

    void Invok()
    {
        StringCollection sc = new StringCollection();

        sc[0] = "Hello";
        sc[1] = "World";

        Console.WriteLine(sc[0]); //Hello
        Console.WriteLine(sc[1]); //World
    }
}

索引器的调用方式类似于数组的索引。
索引器同样可以重载,只要参数列表不同。

构造器

声明一个类后,需要调用他的构造器来声明实例。
对于完全没有声明任何构造器的类型,编译器会自动合成一个无参构造器。

C2 c = new C2();

class C2 
{
}

主构造器

在类后面直接加括号声明参数,这将成为这个类型的主构造器。
主构造器不能拥有逻辑。

除了构造器以外的成员,都可以访问主构造器里的参数。
如果有属性或方法访问,那么这些参数会作为匿名字段储存。
如果只是作为字段的赋值使用,那么不会储存这些参数。

class Point(int x, int y)
{
    int X => x;
    int Y => y;
    double Length => Math.Sqrt(x * x + y * y);
}

调用构造器时,也需要传入这些参数。

Point p = new Point(3, 4);

当定义了任何一种构造器后,系统就不会自动合成无参构造器了。

次构造器

在类的内部可以额外声明更多的构造器。构造器同样可以进行重载。
构造器没有方法的返回值,方法名和类名一样。

构造器有以下特点。基本上,构造器就是用来做内容的初始化工作的。

  • 构造器必定会被调用,且先于其他方法被调用。
  • 构造器只会执行一次。
  • 可以为只读字段赋值,或者使用init访问器。

构造器通常会使用和字段,属性同名的参数。
方法中可以使用this来访问实例成员。不限于构造器,普通方法和访问器也可以这样。

class Circle
{
    double radius;

    Circle(double radius)
    {
        this.radius = radius;
    }
    double Area => Math.PI * radius * radius;

    double Circumference => 2 * Math.PI * radius;
}

构造器链

构造器如果希望调用其他的构造器,则只能在方法执行开始前进行调用。
为此他有特殊的语法。在参数后面加:this()来调用。
如果类有有参的主构造器,那么次构造器必须使用构造器链直接或间接调用主构造器。

class Point(int x, int y)
{
    int X => x;
    int Y => y;
    double Length => Math.Sqrt(x * x + y * y);

    Point(int value) : this(value, value) { }
    Point() : this(0) { }
}

终结器

和构造器相反,终结器是在一个对象被清理时触发的。
它由.Net调用,我们无法主动调用他,所以不能有参数,也不能有访问修饰符。
他的语法是在构造器前加一个~

class Waste
{
	~Waste()
	{
		Console.WriteLine("一个垃圾被清理了");
	}
}

不过.Net不是时刻监视引用类型是否不再使用的,只会在觉得内存占用过多,
或内存不够的时候执行一次清理。所以如果想观察到它,需要创建很多对象。

for (int i = 0; i < 1000_000; i++)
{
	new Waste();
}

解构方法

解构方法可以让实例能像元组一样被析构,或使用模式匹配的位置模式。
解构方法是公开无返回值的,名为Deconstruct的方法。所有参数均为out参数。

class Point
{
	public int X;
	public int Y;

	void Deconstruct(out int x, out int y)
	{
		x = X;
		y = Y;
	}

	void Deconstruct(out int x, out int y, out double length)
	{
		(x, y) = this;//像元组一样解构
		length = Math.Sqrt(x * x + y + y);
	}
}

内部类

类的内部可以再声明类。这称为内部类。
这通常意味着这个类是专属于自己的,用于辅佐自己的东西。
对其他人没有多大用处。

class Barrack
{
    int level;

    class Marine
    {
        int Atk;

        void Init(Barrack barrack)
        {
            Atk += barrack.level;
        }
    }
}

访问权限

默认情况下类成员是不能被外部访问的。如果要公开给外部需要加上访问权限修饰符。

class Point
{
    public int X;
    public int Y;
}
Point p = new Point();
p.X = 12;
p.Y = 12;

访问权限列表

调用方的位置 public(公开) protected internal protected(保护) internal(内部) private protected private(私有)
成员和内部类 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
派生类 ✔️ ✔️ ✔️ ✔️ ✔️
相同程序集 ✔️ ✔️ ✔️
不同程序集的派生类 ✔️ ✔️ ✔️
任何 ✔️

默认访问权限

成员 默认(没写修饰符时)可访问性 允许的成员的声明的可访问性
命名空间 public 无(不能添加修饰符)
枚举 public 无(不能添加修饰符)
顶级类 internal internal 或 public
嵌套类 private 全部
类成员 private 全部
嵌套结构 private 除了带有protected的访问权限。
  • 尽管构造器默认是给别人调用的。但他的默认访问权限也是私有的。你必须主动添加。
  • 属性的访问器可以单独添加访问权限。这样可以声明出只有自己可以修改的属性。
    public int Age { get; private set; }。这也是自动属性的一种用法。

命名约定

具有publicprotected修饰的所有类成员,都意味着将会被他人使用。
为了代码风格的一致性,约定公开的类成员,以驼峰命名法。

  1. 使用英文作为名字
  2. 把所有的空格后的第一个字母大写,然后去掉所有空格
  3. 把首字母大写。

例如:超光速

  1. faster than light
  2. fasterThanLight
  3. FasterThanLight

不公开的命名规范,没有统一。

封装

为什么要阻止调用者访问所有的东西呢?

  • 对于不想知道所有东西的人来说:如果把你带到飞机上的驾驶舱,你看着眼前琳琅满目的按钮你会怎么想?但是,如果我只给你6个键,上下左右前后。有些人可能就敢说会开飞机了。
  • 对于想知道所有东西的人来说:不允许外部修改一些关键数据。例如我游戏只做了70关。然后调用者一改,跳关到80关。那我怎么运行呢?
  • 对于你自己写的代码而言,你可能觉得没有必要,因为想改就改。但是请记住,真实的开发绝对不会是靠你一个人就能完成的。你可能会下扩展包,可能会用你的同学同事写好的代码。有可能很久以后你想起来你写的一个代码刚好能解决问题,但是已经看不懂你写的具体内容。

职责

在定义类的时候,应该先想好它应该做什么,规划他的职责范围。
在你只有一个地方使用的时候,你可能觉得无所谓,写谁身上都一样。

但是如果东西多起来了,可能就会出现重复的代码。

但是如果把恢复生命的方法,写在人物里面,那么就只需要写一份恢复生命
而且本来这个操作修改的也是人物自己的东西,恢复生命,本应是人物的职责。
这样,以后不管是谁使用人物,都可以直接使用他的恢复生命,不需要自己写一份了。

实例和静态

这两词难以理解。我们借用一下民法中的术语种类物特定物

实例,特定物,是可以说这个那个的东西。
你去商场买电视,在你付钱以后,这个电视就是属于你的了。
你的东西你想把他当场砸掉都行。

类,种类物,是指整个概念,比如电视这个概念。
你买下的是这个电视,所以你只能砸这个电视
你不能因为你买了电视+商店里其他电视是电视就觉得自己可以砸掉商店里其他电视了。

实例成员,是需要构建实例才存在的概念。比如鸭子的重量,必须指定一个鸭子才能讨论。
静态成员,只要有概念存在就可以讨论。比如鸭子是两条腿。不需要讨论哪只鸭子。

静态成员

在一个成员前加static修饰就会变成静态的。
实例成员对于每一个实例都是不一样的,他们互不干扰。
但是静态成员是跟随类的,所有实例访问到的都是同一份静态成员。

Cat cat1 = new Cat(30, 10);
Cat cat2 = new Cat(20, 20);
cat1.Show();
cat2.Show();
cat1.Weight = 60;
cat1.Height = 50;
Cat.Legs = 8;//静态成员必须直接通过类名访问
cat1.Show();
cat2.Show();//实例字段没有变化,但腿的数量变成了8
class Cat
{
	public int Height;
	public int Weight;
	public static int Legs;

	public Cat(int height, int weight)
	{
		Height = height;
		Weight = weight;
	}

	public void Show()
	{
		Console.WriteLine("身高" + Height);
		Console.WriteLine("体重" + Weight);
		Console.WriteLine("腿的数量" + Legs);
		Console.WriteLine("===============");
	}
}

this

静态成员也可以有属性,方法,字段。但唯独不能有索引器。因为this的含义就是当前实例。
索引器的语法this[ index]的this就是表示你的变量,只是声明的时候不知道你变量叫什么。

在方法的内部可以通过this访问实例成员,通过类名访问静态成员。这在参数和成员同名时很有用。

class Dog
{
	public int Height;
	public int Weight;
	public static int Legs;

	public Dog(int Height, int Weight, int Legs)
	{
		this.Height = Height;
		this.Weight = Weight;
		Dog.Legs = Legs;
	}
}

静态构造器

静态字段同样可以有只读字段,也同样只能在构造器里修改。
不同的时,静态字段的初始值可以使用其他静态成员参与表达式中。
会按照顺序赋值,还没有赋值的字段在表达式中会以默认值计算。

静态构造器会在这个类第一次被访问时(不是程序启动时)由.Net调用,
所以同样不能添加访问修饰符和参数。

静态成员先于所有实例创建。实例字段的初始值可以使用静态成员参与表达式。

class Duck
{
	public int Height;
	public int Weight;
	public static readonly int Legs;

	static Duck()
	{
		Legs = 2;
		Console.WriteLine("鸭子有两条腿");
	}
}
Console.WriteLine("还没有使用鸭子");
Console.WriteLine(Duck.Legs);

静态类

可以给类声明为静态,这样就无法创建他的实例。
无法创建实例的静态类,讲无法拥有任何实例成员,包括编译器自动添加的无参构造器。
一般来说都是一些只有方法的工具类才这样做。

static class HelloWorld
{
	public static void Hello(string name)
	{
		Console.WriteLine("你好," + name);
	}
}

c#笔记-定义类

扩展方法

在顶级(不是内部类)静态类中,方法的第一个参数可以添加this进行修饰。
在使用this修饰的类型的值时,可以像调用实例方法一样调用这个静态方法。

static class Tool
{
	public static void Hello(ref this bool b)
	{
		b = !b;
		Console.WriteLine(b + "被逆转了");
	}

	public static void Hello(this string s)
	{
		Console.WriteLine("你好" + s);
	}
}
string s1 = "世界";
bool b1 = true;

s1.Hello();//像实例方法调用
b1.Reverse();//不需要添加ref,修改会作用到这个变量上
Tool.Hello(s1);//也能正常用静态方法调用。
Tool.Reverse(ref b1);//只有值类型才能声明ref扩展方法

运算符重载

使用operator可以为这个类型定义运算符,一些规则如下

  • 参数至少有一个是自己类型
  • 对于二元运算,参数的顺序是有影响的(有些运算不满足交换律)
  • 不能在双方类型定义相同顺序和类型的运算符,会出现歧义
  • 必须有返回值,不能是void
  • 一些运算符必须成对出现,但对于返回bool的,不要求互斥。

关于哪些运算符可以重载,请参阅之前的文章

class Speed
{
	public int MetrePerSecond;

	public Speed(int metrePerSecond = 0)
	{
		MetrePerSecond = metrePerSecond;
	}

	public static bool operator !(Speed L) => L.MetrePerSecond != 0;

	public static int operator ~(Speed L) => -L.MetrePerSecond;

	public static Speed operator +(Speed L, Speed R) 
		=> new Speed(L.MetrePerSecond + R.MetrePerSecond);
}

自增和自减

++--要求返回值类型必须是自己。
当一个变量完成了++--后,这个变量会执行一个赋值操作,
用这个运算符的返回值将他替换。

true和false

一个类型可以重载true运算符,他将能作为条件,放入到ifwhile.三元运算符中作为条件。
不过,他还是不能直接给bool变量赋值或是以其他形式当作bool

虽然true运算符要求同时重载false运算符,但false的作用极其有限。
作为条件时只会使用true运算符。false运算符唯一的作用是

  1. 你需要重载&运算符
  2. 你的&运算符的返回值类型要和自己一样
  3. 然后你就能使用&&逻辑运算符,运算规则是false(x) ? x : x & y

自定义类型转换

类型转换使用implicit(隐式),explicit(显示)之一,加上operator指定。
参数和返回值其中有一个是自身的类型。

class Electric
{
	public static explicit operator Magnetism(Electric L) => new Magnetism();
}

class Magnetism
{
	public static implicit operator Electric(Magnetism L) => new Electric();
}

转换没有传递性,但每一个隐式转换都可以以显示转换调用。
有必要的话可能需要使用这种方式转换(生物能)(化学能)(热能)电能

命名空间

定义命名空间

类同样不能重名。为了区分类,可以使用命名空间隔离他们。
命名空间的作用类似于文件夹。不同文件夹下的文件是可以同名的。

namespace Plain//郊外
{
	namespace Castle//古堡
	{
		class Ghost
		{ }//幽灵
	}

	class wildBoar
	{ }//野猪
}

声明命名空间时可以一次性声明多层级的命名空间,使用.隔开

namespace Plain.Castle
{
	class Candle//诡异的蜡烛
	{ }
}

使用文件命名空间,可以指定该文件下所有类都处于此空间中。
但不能再声明其他命名空间,或使用顶级语句。

namespace Plain.Castle;

完全限定名

在调用有重名的类或没有引用命名空间时,
需要带上他的完整命名空间名。
对于没有命名空间的,使用global::(对,是两个冒号)表示根路径。

class Boo { }

namespace A.B.C
{
	class Boo { }
}

调用:

global::Boo boo1 = new global::Boo();
A.B.C.Boo boo2 = new A.B.C.Boo();

引用命名空间

在文件的开头,或一个命名空间的类定义之前,可以使用using引用命名空间。
引用命名空间后,在作用域内使用这些命名空间下的类不需要再写完全限定名。

namespace A.B.C
{
	class Foo { }
}
using A.B.C;
Foo foo = new Foo();

类型别名

使用using可以用类似变量赋值的操作,给一个类型指定一个别名。

namespace Gas
{
	class CarbonDioxide { }
}
using CO2 = Gas.CarbonDioxide;
CO2 co2 = new CO2();

静态引用

使用static using可以导入一个类型的所有静态成员,
在不点出他的类名的情况下使用他的静态成员。

using static System.Int32;//int关键字就是这个类型的类型别名

int int32 = Parse("32");
int max = MaxValue;

类的成员常量也会被认为是静态成员。

全局引用

使用global修饰的命名空间引用,类型别名,静态引用,会作用到这个程序集下的所有文件。

global using System;

在你的控制台模板项目生成时,就带有一些默认的全局引用。
可以在你的编译器左上角看到他们。
c#笔记-定义类文章来源地址https://www.toymoban.com/news/detail-437072.html

到了这里,关于c#笔记-定义类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python学习笔记(四):函数的定义、函数的返回值、None类型、函数说明文档、函数的嵌套调用、局部变量、全局变量、global关键字

    目录 一、函数介绍 1. 函数是: 2. 使用函数的好处是: 二、函数的定义: 三、函数的参数 1.传入参数的功能是: 2.函数的传入参数 - 传参定义 3.注意事项: 4.练习:测量体温 四、函数的返回值 1.函数返回值的定义 2.None类型 五、函数说明文档 六、函数的嵌套调用 七、变量的

    2024年02月05日
    浏览(41)
  • C# -- static 关键字

    一、static static ,用于修饰类,字段,属性,方法,构造方法等。被 static 修饰的类称之为“静态类”; 被 static 修饰的成员称之为“静态成员”,被修饰过的成员分别称为:静态字段,静态属性,静态方法,静态构造方法。 二、静态字段 1.概念 被 static

    2023年04月19日
    浏览(26)
  • C#中的ref关键字

    1、传递的是参数的值(数据的副本)而不是原始数据本身。 2、函数内部对值参数的修改不会影响到原始数据。 3、通常用于传递基本数据类型(如整数、浮点数、布尔值)或不可变对象(如字符串、元组)。 4、值参数的传递是一种传值调用(Call by Value)。 示例代码 运行结

    2024年02月05日
    浏览(39)
  • C# void 关键字学习

    C#中void是System.Void的别名; 可以将 void 用作方法(或本地函数)的返回类型来指定该方法不返回值; 如果C#方法中没有参数,则不能将void用作参数;这是与C语言不同的,C语言有 int func(void) 这样的; 做一个winform示例看一下;

    2024年02月10日
    浏览(29)
  • C# const关键字学习

    你居然不知道const?今天在做项目的时候别人问我的,我确实不知道这个,今天我们就来一起学习一下const定义局部变量,这个对于常数变量非常的友好的,可以提高程序的运行效率,因为它是在编译时的操作,所以我们必须要学习一下,这不就是提

    2024年01月22日
    浏览(42)
  • C#中的`out`关键字

    C# 中的 out 是一个用来在方法调用时传递数据的修饰符。它允许你在方法内部创建一个临时的变量,用于接收传递进来的参数值,并在方法执行完毕后,将该变量的值返回给调用方法的对象。out 主要用于那些需要知道方法执行结果的参数上。 在 C# 中,out

    2024年02月22日
    浏览(41)
  • C#中out关键字

    在C#中可以使用out,指定所给的参数是一个输出参数。out的使用方式与ref相同,都是在函数定义和函数调用中用作参数的修饰符。 运行结果,如下图所示: 实际上,out的执行方式与引用参数几乎完全一样,因为在函数执行完毕后,该参数的值将返回给函数

    2024年02月05日
    浏览(41)
  • 【ES6】js 中class的extends、super关键字用法和避坑点

    在JavaScript中,使用class可以实现面向对象编程。其中,extends和super是两个非常重要的,它们分别用于实现类的继承和调用父类的方法。 一、extends extends用于实现类的继承,它可以让一个子类继承父类的属性和方法。使用extends时,需要指定要

    2024年02月09日
    浏览(26)
  • C# 使用SIMD向量类型加速浮点数组求和运算(4):用引用代替指针, 摆脱unsafe关键字,兼谈Unsafe类的使用

    作者: zyl910 目录 一、引言 二、办法说明 2.1 历史 2.2 局部引用变量与引用所指的值(类似指针的 地址运算符 、间接运算符 * ) 2.3 重新分配局部引用变量(类似指针直接赋值) 2.4 引用地址调整(类似指针加减法) 2.5 引用地址比较(类似指针比较) 2.6 重新解释(类似C++的

    2024年02月15日
    浏览(32)
  • C#关键字Virtual用法详解

    本篇讲解C#Virtual用法 目录 定义 特性 实例 virtual 用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。 虚拟成员的实现可由派生类中的重写成员更改

    2024年02月15日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包