C#中类 类型的变量是通常所说的“对象么?”类的实例又是什么?

2023-10-09 04:48:34 +08:00
 huzhikuizainali

我面向对象的知识来自于 matlab ,比较简单。比如你定义了一个 class A ,那么你实例化一个对象就用 a=A(); 就可以了(假设类 A 的构造函数允许参数为空) 但是到了 C#,我发现比较复杂。请看下面的截图。给出了一个 “类 类型的变量” 概念。请问这个变量是通常说的“对象”么? 和“类的实例” 是一回事么? 因为这段文字中没有给出“类的实例”的明确定义( matlab 中对象和类的实例是一回事)

                 截图

之所以纠结这个问题,是因为下面的情况是在 matlab 面向对象程序中从未遇到的情况。mgr 到底是哪个类的对象呢? IExtensionManager 的? FileExtensionManage ? 虽然 FileExtensionManage 是 IExtensionManager 的子类 ,但是二者的字段 数量可能都不一样,最后 mgr 到底以谁为模板生成对象了呢?会不会出现鼠头鸭脖的矛盾呢?

                 截图

1116 次点击
所在节点    C#
7 条回复
cxe2v
2023-10-09 08:43:55 +08:00
mgr 是 FileExtensionManage 的实例,IExtensionManager 是接口,定义了一堆未实现的方法,FileExtensionManage 通过:这个符号继承了 IExtensionManager 内的方法定义,具体实现是在 FileExtensionManage 这个 class 里
huntagain2008
2023-10-09 11:45:04 +08:00
我作为小白的回答如下:
> mgr 到底是哪个类的对象呢? IExtensionManager 的? FileExtensionManage ?
mgr 当然是 FileExtensionManage 的对象。

> 虽然 FileExtensionManage 是 IExtensionManager 的子类 ,但是二者的字段 数量可能都不一样,最后 mgr 到底以谁为模板生成对象了呢?会不会出现鼠头鸭脖的矛盾呢?

子类这个说法应该不对。': IExtensionManager'只是实现这个接口,并不是子类。
mgr 声明的变量类型是 IExtensionManager ,对象依然是 FileExtensionManage 为模版生成的。
不会有什么矛盾,只是增加 IsValid(fileName)的方法。
Jax6
2023-10-09 16:15:15 +08:00
这里有一个是基类或接口的概念,可以说 FileExtensionManage 类继承了 IExtensionManager 接口,mgr 是 FileExtensionManage 的实例对象,即可以调用 IExtensionManager 中抽象的在 FileExtensionManage 中真实实现业务的接口。是更细一级的概念。这个就像 C#中类都是派生于基类 object 一样。相当于一个大纲,继承则会在保持原有大纲的情况下进行内容的丰富。同理,你也可以把你的 FileExtensionManage 类赋值给 obj,也是没问题的。
object i = new FileExtensionManage();
huzhikuizainali
2023-10-09 17:32:45 +08:00
@Jax6 谢谢回复
我看了一下 C#接口的介绍,结合了类 类型的变量的概念。产生了 两个派生问题:

1 、语法层面的问题 假设要实例化一个“纯”A 类的对象,C#中的语法往往是 A a= new A() ; , matlab 中只需要 a= A() ; 。我觉得 C#中 a 前面那个 A 很多余啊。难道不能在用户不特别声明的情况下默认 a= new A();就是实例化一个“纯” A 类的对象么?

2 、“非纯”A 类的情况。我在 matlab 中学过抽象类,也知道抽象类的好处和价值。但是在 Matlab 中只接触过如下思路,假设 A 是抽象类,B 和 C 是继承了 A 的具体类。然后 b= B(); c=C();就可以了,比如 B 类是法师 C 类是射手,那么就可以实现 b.attack c.attack 多态下的不同攻击方法。但是我无法理解 A b=new B() ; A c= new C(); 这个 A 在这里的作用。难道是告诉编译器对象 b 和对象 c 是 接口 A 下面的 子类的对象么?完全没必要啊,因为 public class B:A 已经阐述了这种继承关系。
其次 A b=new B(); 和 B b= new B(); 有什么不同呢?
Zhuzhuchenyan
2023-10-09 20:30:22 +08:00
1. C#的语法允许使用 var 关键词来自动推断类型,例如 A a = new A()可以写成 var a = new A()
2. 这个问题算是比较常见的了

2.1 A b=new B(); 和 B b= new B(); 有什么不同呢?
相同点:同样都是调用 B 的构造方法,b 同样都是 Class B 的实例
不同点:A b=new B();这样的方式下无法调用派生类 B 的方法,只能调用基类 A 的方法

2.2 存在这样的方式主要是有的时候我们只关心基类而不关心派生类,单独使用确实比较奇怪,这里更多是想向你阐述这样的一种转换方式是合法的。

其他的使用方式,比如说,B 是法师,C 是射手,基类 A 中有个方法 Attack(A target),接受一个 A 类型的对象并攻击他,那么就可以这样使用
var b = new B()
var c = new C()
b.Attack(c) // 合法,此处形参中将 c 隐式转换为 A 了
huzhikuizainali
2023-10-09 23:50:57 +08:00
@Zhuzhuchenyan 谢谢谢谢回复
1.如你所说,确实如此
2.1 如果想实现“ A b=new B();这样的方式下无法调用派生类 B 的方法,只能调用基类 A 的方法”。—————要实现这个目的,完全可以将 B 类中相关方法设为私有,这样选择权在类的设计者手中,且更灵活。所以 C#允许 A b=new B()是否还有其他深意?特别是 c#中有 A 类 类型的变量 b 这种概念,在 Matlab 中 b 就是对象。不会叫作变量。我不知道这是翻译习惯的问题?还是二者概念确实不同?
huntagain2008
2023-10-11 14:35:19 +08:00
小白我的理解
> C#允许 A b = new B()是否还有其他深意?
如#3 所说,是更细一级的概念。我问了下 ChatGPT ,它告诉我:
在 C#中,当我们使用 object 或 IExtensionManager 来声明一个变量时,该变量将被视为对象的基类,因此只能调用基类中定义的方法和属性。而无法直接调用派生类中特有的方法和属性。

至于深意,ChatGPT 的回答是:
1. 多态性:通过将变量声明为基类类型,我们可以在运行时将其赋值为不同的派生类的实例。这样做的好处是,可以使用相同代码来处理不同类型的对象,实现代码的可扩展性和灵活性。通过多态性,可以通过基类类型的变量来处理不同派生类的对象,提高代码的可重用性和可维护性。
2. 封装性:将变量声明为基类类型有助于实现封装性,即隐藏派生类的具体实现细节。将对象的具体类型和实现细节封装起来,而只暴露基类的公共接口。这样做可以实现代码的模块化和解耦,提高代码的可维护性和可扩展性。

> c#中有 A 类 类型的变量 b 这种概念,在 Matlab 中 b 就是对象。不会叫作变量。我不知道这是翻译习惯的问题?还是二者概念确实不同?

我的理解是首先变量的定义是在高级程序设计语言允许使用描述性的名字指向主存储器中的位置,而不必再使用数字地址,这样的名字称为变量。那么,一般的变量指的都是基本数据类型,比如整型、布尔型、字符型等。但是,教科书也提到像 GIF 、JPEG 和 HTML 这样的类型可能也要像整型和浮点型一样通用。而面向对象范型使程序员可以在一门程序设计语言提供的的原语类型的基础之上扩展可用数据类型的指令系统,这种能力是面向对象范型的一个著名的特征,所以这不是翻译习惯,就是变量,只是声明的一个类类型的变量。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/980064

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX