C# 基础知识系列- 4 面向对象
csdh11 2025-03-06 13:53 13 浏览
面向对象
面向对象是一个抽象的概念,其本质就是对事物以抽象的方式建立对应的模型。 简单来讲,比如我有一只钢笔,那么我就可以通过分析,可以得到 这只钢笔的材第是塑料,品牌是个杂牌 ,里面装的墨是黑色的,可以用。这时候就能建立一个钢笔的模型,它在这里应该有这些属性:
图是一个不正确的UML类图,但是可以简单的概述一下我们抽象的结果。这个图就描述了一个我们抽象出来的钢笔类应该有哪些特性,而我手里的那只钢笔就可以看做是钢笔类的一个实例。 简单来讲,面向对象编程就是针对一个事件或者说一个过程,找到这个过程中参与的所有人、事务或者相对独立的个体,按照他们在这个过程中表现,提取出他们的特性,描述他们的行为,然后按照类别不同再抽象出类来。 所以,类是事物的概念抽象,事物是类的特殊实例。
创建一个类
上面简单的介绍了面向对象的概念,现在先创建一个C#类,然后介绍一下这个类需要注意的地方:
public class Person
{
private static int count;
public static int Count
{
get { return count; }
set { count = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public Person()
{
Name = "";
Count = Count + 1;
}
public Person(string name)
{
this.Name = name;
}
public void SayHello()
{
}
}
其中: private string name;和private static int count;这两个在C#中称为Field,也就是字段的意思; public static int Count 和public string Name 这两个在C#中称为Property,也就是属性的意思。 当然,不是说一个是private就叫字段,另一个是public就称之为属性,而是因为属性有get和set来控制访问和赋值的行为。
public Person() 和public Person(string name)是构造方法,所谓的构造方法就是初始化一个实例的方法,调用形式如下: Person p = new Person() 通过new关键字+类名+对应的参数列表即可。构造方法没有返回类型,方法名必须是类名,可以有任意个参数。
面向对象的三大特性
面向对象的三大特性是封装、继承、多态。我把它们称为面向对象面试三巨头,因为一旦面试,如果有面向对象的问题绝对会问到这三个特性。这里先简单介绍一下三大特性,
- 封装:对象的方法实现对外是隐藏的,就像我们在不拆开钢笔之前很难知道钢笔的墨水是怎么流动然后写出字的;
- 继承:子类天然拥有父类的属性和方法,假如我们还有一只特种钢笔,那么我们可以把这只特种钢笔抽象出的类认为是钢笔的子类,这只特种钢笔跟钢笔一样,可以用来做钢笔能做的事,虽然有时候不好用;
- 多态:简单来讲就是多种状态,对于面向对象来说,就是方法重写和方法重载。比如说,我们去找领导签字,领导在忙让我们把文件放那边,过一会领导派人送过来签好字的文件。如果领导有多只钢笔,那么领导用哪只笔、在什么时候、用什么姿势对于我们来说就是不确定的状态,这就是多态的一种。
访问控制符
在将三大特性之前,先介绍一下 C#的访问控制。C#常用的访问控制分为四种:
- private: 限定只有同属于一个类的成员才可以访问,如果限定一个类是私有类,那么这个类必须是内部类
- protected: 限定当前类的成员、子类可以访问,不能用来限定外部类,同private一样,如果限定类是受保护类,这个类必须是内部类
- internal(default):默认访问权限,对于类和方法来说,限定同一个DLL可以访问,其他DLL不能访问。区别是类的 internal 关键字可以省略,方法如果省略访问权限符,则默认是protected
- public:公开,所有能引用类的地方都能访问类里的public对象,这是最开放的权限。
C#还有更多的访问控制,不过常用的只有这四种,更多的可以参照【官方文档】。
封装
封装简单来讲就是调用方不知道被调用方的具体实现以及内部机制,就像我们看别人只能看到外表缺看不到器官的运作(当然除非你是医生)。 那么封装有什么好处呢:
- 对外隐藏实现,防止外部篡改引发安全问题
- 减少不必要的关联,被调用方需要调用方提供参数,但除此之外调用方只需要静待被调用方返回结果就行
- 打包一系列的操作,防止中间发生变故
比如说一个钟表,给我们一堆零件,在没有拼接、安装好之前也就是封装好,这个钟表是不能正常使用的。只有我们按照一定逻辑,将零件安装好之后(封装),再装上电池或上发条(调用) 钟表才会转起来。 简单的用代码介绍一下:
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.SayHello();
}
}
public class Person
{
private static int count;
public static int Count
{
get { return count; }
set { count = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public Person()
{
Name = "小明";
Count = Count + 1;
}
public Person(string name)
{
}
public void SayHello()
{
Console.WriteLine("你好,我叫"+Name);
}
}
简单看一下,对于Program类来讲,Person的SayHello是怎么实现的完全不知情。这就是封装的意义。
继承
C#的继承是单继承,也就是说一个类只有一个父类,如果不指明父类,那么它的父类就是object。换句话说,object是C#继承体系里的根,也就是所有类的祖先类。 C#的继承用: 表示,即 class B: A表示B继承A。
public class A
{
public virtual void Say()
{
}
public void Look()
{
}
}
public class B : A
{
public override void Say()
{
}
}
上述代码建立了一个简单的继承体系。那么问题来了,继承有什么用呢?简单来讲,对于A和B在Say方法有不同的实现,对于调用方来讲,它们的表现应当是一致的。换句话说,就是所有用到A的地方,都能用B来代替,这不会出现任何问题。 继承可以简化很多行为(方法)一致的写法。如示例所述,B类在Look上与其父类A类有着一致的行为和表现,那么B就可以省略了Look的定义和描述,沿用父类的方法。通过继承可以很快地建立一套丰富的方法体系。子类每一次对父类的方法补充都会在子类里体现出来。所以继承可以说是面向对象的核心体系。
有个关键字需要额外的讲解一下saled,如果看到一个类有这个标记,那么需要注意了,这个类是不可被继承的类。
多态
多态的实现就是通过类的继承和方法的重载实现的。类的继承主要通过重写父类方法或者覆盖父类方法来实现的,主要关键字就是 virtual、override、new。 具体的介绍是:
- virtual 关键字声明函数为虚函数,意思就是子类可能会重写该方法
- override 用在子类,用来声明该方法是重写父类的方法
- new 跟实例化对象的new不同,这个放在方法前的意思是该方法会隐藏父类方法的实现。
public class A
{
public virtual void Say()
{
//省略实现
}
public void SetName()
{
//省略实现
}
}
public sealed class B:A
{
public override void Say() //重写父类方法
{
//省略实现
}
public new void SetName() // 覆盖父类方法
{
//省略实现
}
}
重写和覆盖的区别在哪呢:
A a = new B();
a.Say();// 调用的是 B中 Say方法
a.SetName();//调用的是A的SetName 方法
B b = (B)a;
b.SetName();//调用的是B的SetName 方法
b.Say();// 调用的是 B中 Say方法
类和接口
C#中类和接口的声明方式不同,类用的关键字是class,接口用的是interface。而且类是继承,接口是实现,一个类只能有一个父类,接口可以有多个。 接口需要注意的地方就死,接口所有的方法都是public的,因为接口就是用来定义规范的,所以一旦它的方法访问控制不是public的话,就没什么意义。
public class Demo1
{
}
public interface IDemo
{
string Method();
}
public class Demo3 : Demo1, IDemo
{
public string Method()
{
return "test";
}
string IDemo.Method()
{
return "test2";
}
}
接口的实现和类的继承都是 : ,先继承后实现。
观察示例代码,发现Demo3有两个方法public string Method()和string IDemo.Method() 。这两个都是实现接口的方法,不同的地方是它们的使用:
IDemo idemo = new Demo3();
idemo.Method();//返回 test2
Demo3 demo = new Demo3();
demo.Method();// 返回 test
使用接口名.方法名实现方法的时候,这个方法对于实现类构造的对象来说是不可访问的。当然两种方法可以共存,但是不会两个方法都被认为是接口的实现方法。接口优先使用接口名.方法名 作为实现方法,如果没找到则认为同名同参的方法为实现方法。
Object 类 常用方法
object 作为基类定义了四个基本方法,这四个方法是所有子类都有的方法,也是一个核心方法:
- Equals(object obj) 这是一个很重要的方法,它是 C#中判断两个对象是否相等的依据,也就是 == 运算符的结果,如果不重写这个方法的话,返回的结果是两个对象是否指向同一个引用地址。
- GetType() 返回这个对象的类型,这是反射机制中重要的一块
- ToString() 返回字符串,获得一个对象的文字描述,默认返回的是对象的地址描述信息,这个方法建议重写
- GetHashCode() 返回 Hash值,某些集合和程序机制会以HashCode作为元素的相等性判断依据,所以在重写 Equals 之后也要重写 这个方法,并保证两个方法对于相同的对象做相等性结果判定是应该表现一致。
扩展方法
C# 有一个很重要的机制就是扩展方法,扩展方法表现出的跟类自有的方法调用结果一致。 具体写法如下:
public static class Methods
{
public static string Test(this Person person)
{
return "test";
}
}
需要注意的是,扩展方法所在类必须是静态类,扩展方法必须是静态方法,扩展方法第一个参数就是扩展的元素对象,用this标记。
不过很多人对扩展方法褒贬不一,有人认为扩展方法极易破坏继承链,导致一些不必要的麻烦;有人认为扩展方法就跟工具方法一样,而且可以优化调用方式,统一使用风格。
不过我看来,扩展方法利大于弊。因为扩展方法可以在不修改原有类的基础上增加功能,同时它也是一个工具类,跟普通的方法是一致的。
- 上一篇:C# 属性
- 下一篇:C# WinForms自定义控件怎么添加自定义属性
相关推荐
- IDEA界面太丑??尝试一下这几个插件
-
前言IntelliJIDEA主要用于支持Java、Scala、Groovy等语言的开发工具,同时具备支持目前主流的技术和框架,擅长于企业应用、移动应用和Web应用的开发。IntelliJi...
- 小巧 Vue 页面滚动进度条组件ScrollProgress
-
今天给大家分享一个轻量级Vue.js全屏滚动进度条组件VueScrollProgress。vue-scroll-progress一款基于vue.js构建的页面滚动进度条组件,...
- 基于vue实现可视化拖拽编辑器,页面生成工具,提升前端开发效率
-
项目介绍基于vue实现的可视化拖拽编辑器,实现页面生成工具,提升前端开发效率。可以基层到移动端项目作为自定义json直接生成UI页面。项目特点功能特点...
- 优秀 vue+heyui 后端管理系统HeyUI-Admin
-
今天再给小伙伴们推荐一款成熟的企业中后台管理系统HEYUI-Admin。heyui-admin基于vue.js和heyui组件库构建的后台管理系统。包含基础表单/表格功能,拓展组件(图表、富文本编辑...
- 响应式 Vue.js 前端组件化框架Xvue-UI
-
今天给小伙伴们推荐一款超不错的Vue轻量级组件框架XVueUI。xvue-ui基于vue2.x构建的响应式前端组件化框架。轻量级、易于上手,提供...
- 《基于SpringBoot+Vue的在线视频系统设计与实现》开题报告
-
【计算机毕业设计案例】基于SpringBoot+Vue的在线视频系统设计与实现_哔哩哔哩_bilibili...
- 超好用 Vue.js 图片裁切组件Vue-ImgCutter
-
今天给小伙伴们分享一个超棒的Vue图片任意裁剪插件VueImgCutter。vue-img-cutter基于vue2.x构建的轻量级剪切图片组件。支持移动图像、放大缩小图片、任意移动图片、固定比...
- Vue 3 进阶用法:异步组件(vue 异步组件原理)
-
一、代码分割一个大型前端应用,如果所有代码都放在单一文件,体积会特别大,下载时间长,白屏时间久,用户体验差。...
- 源码补丁神器—patch-package(源码助手怎么用)
-
作者:张浩一、背景vue项目中使用vue-pdf第三方插件预览pdf,书写业务代码完美运行,pdf文件内容正常预览无问题。后期需求有变,业务需求增加电子签章功能。这个时候pdf文件的内容可以显示出...
- 经验分享:Vue2 项目升级 Vue3 + Element Plus,借助Deepseek手动升级
-
Vue3出来好久了,我开发的项目还在使用Vue2框架,一般情况下不考虑升级,但是最近需要接入工作流程引擎之类的,看了下Vue2生态下操作空间不是很好,那索性尝试升级Vue3吧。一番操作下来,升级成功,...
- 34K Star!史上最全JavaScript资源库 awesome-javascript
-
34KStar!史上最全JavaScript资源宝库大揭秘引言在GitHub上,有一个备受瞩目的JavaScript资源仓库,以其全面的内容和精心的分类,成为了众多开发者的必备参考。这个拥有超过...
- 基于 Vue.js 磁片栅格布局组件VueGridLayout
-
#头条创作挑战赛#今天给大家分享一个超优秀的vue.js拖拽栅格布局插件VueGridLayout。...
- 6款高颜值 Vue3 PC端UI组件库(vue3开发组件库)
-
马上到国庆了,还没学习或者想学习vue3的小伙伴们有安排上没?这次推荐几个比较流行的VUE3UI组件库,合理利用,又或者学习借鉴都是不错的选择。1、element-pluselement-plus...
- 高性能 vue.js+ztree 树形组件Vue-GiantTree
-
今天给大家分享一款超棒的Vue海量数据渲染树形组件VueGiantTree。vue-giant-tree基于ztree封装的Vue树形组件。轻松实现大数据高性能渲染,适合海量数据渲染场景。zTr...
- 【推荐】2024年推荐的6款开源免费 Vue 后台管理系统模板,建议收藏
-
前言在现今的软件开发领域,...
- 一周热门
- 最近发表
-
- IDEA界面太丑??尝试一下这几个插件
- 小巧 Vue 页面滚动进度条组件ScrollProgress
- 基于vue实现可视化拖拽编辑器,页面生成工具,提升前端开发效率
- 优秀 vue+heyui 后端管理系统HeyUI-Admin
- 响应式 Vue.js 前端组件化框架Xvue-UI
- 《基于SpringBoot+Vue的在线视频系统设计与实现》开题报告
- 超好用 Vue.js 图片裁切组件Vue-ImgCutter
- Vue 3 进阶用法:异步组件(vue 异步组件原理)
- 源码补丁神器—patch-package(源码助手怎么用)
- 经验分享:Vue2 项目升级 Vue3 + Element Plus,借助Deepseek手动升级
- 标签列表
-
- mydisktest_v298 (34)
- document.appendchild (35)
- 头像打包下载 (61)
- acmecadconverter_8.52绿色版 (39)
- word文档批量处理大师破解版 (36)
- server2016安装密钥 (33)
- mysql 昨天的日期 (37)
- parsevideo (33)
- 个人网站源码 (37)
- centos7.4下载 (33)
- mysql 查询今天的数据 (34)
- intouch2014r2sp1永久授权 (36)
- 先锋影音源资2019 (35)
- jdk1.8.0_191下载 (33)
- axure9注册码 (33)
- pts/1 (33)
- spire.pdf 破解版 (35)
- shiro jwt (35)
- sklearn中文手册pdf (35)
- itextsharp使用手册 (33)
- 凯立德2012夏季版懒人包 (34)
- 冒险岛代码查询器 (34)
- 128*128png图片 (34)
- jdk1.8.0_131下载 (34)
- dos 删除目录下所有子目录及文件 (36)