C#中使用属性及get,set访问private字段和直接用public修饰字段的对比和理解
导语
本篇仅作为初学C#的随笔,内容较基础,适合初级水平开发者,浅谈主题中的话题,从两者的相同点,不同点,和如何选三个角度探讨,希望文章能起到抛砖引玉的作用,欢迎补充和纠正。
如果你并不想花费十分钟左右探究背后的所以然,请直接滚(动滚动条)到“public
or 属性”部分
public
and 属性
在我们需要对类中声明的字段(field)进行操作的时候,有两种方法:
- 将字段以
public
修饰,以达到将数据暴露给所有代码的目的 - 将字段以
private
修饰,通过属性(property)与属性访问器(accessor)操作字段
如果你正在看这篇文章,那么肯定有这样的疑惑:“这两种方式有什么实质性的区别么?”,将数据以private
修饰将其对外隐藏、保护,然后又通过定义与之关联的属性,并以访问器来提供访问手段,和直接用public
修饰的区别何在?
public
关键字
顾名思义,不赘述。
查看MS Docs中的public
关键字
private
关键字 属性及其访问器
private
关键字
查看MS Docs中的private
关键字
属性
get
和set
访问器
查看MS Docs中的属性和访问器
相同点
都是类的成员 | 访问的语法相同 | 都提供类的存储 |
---|
引自:查看字段与属性相同点的原文
public
vs 属性
以下示例中:
一个简单的垃圾桶类,包含一个描述垃圾种类的字段
通过public
修饰字段
用户可以将任何字符串类型的数据作为垃圾分类的值
public class GarbageCan
{public string garbageClass;//最高访问级别,除取值类型限制为string以外,没有访问限制,//任意程序中的任意代码可读写
}private static class GarbageClassification
{private static void Main(){GarbageCan can1 = new GarbageCan { garbageClass = "recyclable",};GarbageCan can2 = new Garbagecan { garbageClass = "kitchen waste",};GarbageCan can3 = new GarbageCan { garbageClass = "hazardous",};//如果我们给某个垃圾桶一个并非垃圾分类的赋值呢,比如"cat"}
}
只要你输入的是string
类型的数据,垃圾桶的分类可以被任何人修改为任何值,虽然装满猫咪的垃圾桶很可爱 (>^ω^<)喵,但他们并不是某种垃圾分类啊o(╥﹏╥)o。属性作用之一便是在字段取值类型的约束下再限制字段的取值范围。
通过公有属性操作私有字段
我们引入属性并将垃圾种类字段设为private
:
public class GarbageCan
{private string garbageClass = string.Empty;//最低可见度,类以外的代码无法访问,实现类的封装,//以及对数据的保护public string GarBageClass//定义私有字段的公有属性,属性是字段的自然延伸//一般规范是将对应字段的首字母大写,也有//_garbageClass -> garbageClass的写法{get { return garbageClass;}set { //对输入数据进行检查,只接受正常的垃圾分类名词if (value == "recyclable" || value == "kitchen waste" || value == "hazardous")garbageClass = value;//不合法数据将不会被写入,并输出提示信息 else Console.WriteLine("{value} is not a class of garbage!");}}
在Main()
函数中尝试使用GarbageClass
属性读写private
字段garbageClass
:
private static class GarbageClassification
{private static void Main(){GarbageCan can1 = new GarbageCan { GarbageClass = "cat", };//尝试通过set访问器给私有字段写入无效值GarbageCan can2 = new GarbageCan { GarbageClass = "recyclable", };//通过set访问器给私有字段写入有效值Console.WriteLine($"The first can's for {can1.GarbageClass} garbage.");//通过get访问器读取私有字段Console.WriteLine($"The second can's for {can2.GarbageClass} garbage.");//通过get访问器读取私有字段}
}
以上代码输出:
The first can's for garbage.//输出初始的空字符串
The second can's for recyclable garbage.
对比
可以看到,相比于public
修饰的,直接暴露在外的字段,在set
方法中我们自定义的if
语句起到了对输入值的合理性、合法性进行限制的作用。
属性的其他一些优势
set
方法内的语句除验证写入的数据外,也可以自定义其他语句,比如可以实现在字段值发生改变的时候让其他成员也进行响应的效果。- 另外,在试图读取时我们触发
get
访问器,试图写入则触发set
访问器,可以通过只声明get
/set
,或通过限制set
/get
的可访问性分别控制属性的只读/只写状态。
如:
public class ReadOrWriteOnly
{private bool readOnly = false;private bool writeOnly = false;public bool ReadOnly { get { return readOnly; } }//让属性只读public bool ReadOnly_1 {get { return readOnly; } protected set { readOnly = value; } }//让属性只读public bool WriteOnly { set { writeOnly = value; } }//让属性只写public bool WriteOnly_1 {protected get { return writeOnly; } set { writeOnly = value; } }//让属性只写
}
- 如果访问器内没有自定义的语句,则可以使用自动实现的属性(auto-implemented property)
查看MS Docs中的自动实现的属性
来简化属性,例:
public class UsefulTool
{//未简化的属性private string toolName = string.Empty;public string ToolName { get { return toolName; } set { toolName = value ;} }//自动实现的属性public string ToolName { get; set; } = string.Empty;
}
- 符合类的设计原则“封装性(encapsulation)”,几番周折,属性其实是对字段做了封装
“其实这里体现的就是封装的思想: 将数据与行为进行分离。” 引自:查看Java中为何使用属性的原文
当然public
也有其好处
- 相比于public短短的六个字符,在对敏感度极底的字段的操作时,或许属性的方式会显得冗余了不少,
不同点
方式\对比 | 逻辑性、灵活性 | 存储性 | 访问性 | 安全性 |
---|---|---|---|---|
属性 | 是对字段的自然延伸,有逻辑处理 | 不占用实际内存 | 操作的字段可被其他类间接访问 | 安全 |
public
|
无逻辑处理 | 分配内存空间 | 直接暴露给其他类 | 不安全 |
引自: 查看属性和字段的不同点的原文
public
or 属性
那public在修饰类中字段这方面就一无是处了吗?实际还是要根据情况斟酌,关于什么时候使用什么方法,可以参考以下建议:
“公共字段:
- 允许自由读写
- 取值范围只收数据类型约束而无其他任何特定限制;
- 值的变动不需要引发类中其它任何成员的相应变化;
如果均满足上述条件,那么我们便可以大胆地使用公共字段; ”
“属性
- 要求字段只能读或只能写;
- 需要限定字段的取值范围;
- 在改变一个字段的值的时候希望改变对象的其它一些状态;
如果满足上述条件中的任何一个,就应该使用属性。”
引自:查看public
和属性的适用范围原文
总结
MS Docs是C#的权威参考,其中也包括整个微软生态相关的文档以及教程,非常实用和高效。对于初学者,FreeCodeCamp的入门教程也非常不错C# Tutorial - Full Course for Beginners。
在产生本文中心问题之初,对规范性的概念甚是稀薄,并不能想通为何要先用private
让其不可见后再构建属性让其可见,这不是一对矛盾么。随着理解的深入,在OOP(object-oriented programming)的思想下,通过方法操作数据是此类语言的基本特点,是设计类的原则,让类具有安全性、可维护性,而属性就做到了这一点,尽管你可以继续滥用public
(并不是一棒子打死,参考上文的适用范围),自己写一个方法检查数据的输入,也可以用其他手段控制字段的读写状态etc.,但在大型项目中,很容易牵一发而动全身,类的可维护性非常重要,不论是个人开发者或者团队协作。就文章主题来说,在大型项目中,当需要对类添加新需求时,如果涉及到public
字段所持有数据的修改,比如要将一个Phone
的所有实例的brand
字段全部设为"Fruit"
,使用public
字段你需要修改接口,并修改每个调用处的代码,使用属性只需在set
方法中添加“”实现即可。
或许用近四千字来探讨如此基础的话题显得有些冗余(。-`ω´-),可在“做什么”的背后往往有层出不穷的“为什么”。
C#中使用属性及get,set访问private字段和直接用public修饰字段的对比和理解相关推荐
- Java中,String类字符串拼接 用concat方法 和直接用“+”连接符拼接的区别
在String类中,字符串拼接既可以使用concat方法,也可以直接用连接符进行连接,那么两者有什么相同点和不同点呢,下面小编带大家通过代码一起来看一下. concat方法的使用:public Str ...
- httpsclient 自动获取证书 无证书访问 验证过能直接用
首先实现写一个 实现接口SecureProtocolSocketFactory的类. /***ClassName: bcde*date: 2015年2月26日 下午4:51:01**@author l ...
- Python 中的属性访问与描述符
在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个name属性,那便可以使用foo.name对此属性进行访问.一般而言,点(. ...
- flash AS3.0访问加载的SWF文件中的属性、方法以及类、库中的影片剪辑
对于FLASH,我们可以把任何的可视化元件都看成某个类文件的具体实例,包括swf文件. 我们可以把swf文件看成一个类的具体实例,而它里面拥有个个其他类的实例对象,例如: 我们新建一个loaded.f ...
- python描述符与实例属性_Python 中的属性访问与描述符
在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个name属性,那便可以使用foo.name对此属性进行访问.一般而言,点(. ...
- python私有属性怎么定义_Python中私有属性的定义方式
Python没有类似于Java的private关键字, 但也可以为类定义私有属性. 只需将属性命名变为以__开头, 例如 __field. 示例代码: class Vector2D(object): ...
- php js怎么去掉类属性,如何修改DOM中的属性,类和样式
通过jQuery来获取要修改的DOM元素,然后通过JavaScript中方法来对属性.类以及样式进行修改 今天在本篇文章中将分享的是如何通过修改html元素节点的样式,类和属性来进一步的更改dom,, ...
- SpringMVC js如何获取后台model中的属性值
SpringMVC js如何获取后台model中的属性值 companylist 如何获取 var companylist="${companylist}"; 希望对你有所帮助 个 ...
- python类中的属性分为类属性和实例属性两种_python中类和实例如何绑定属性与方法示例详解...
前言 python类与实例的方法的调用中觉得云里雾里,思考之后将自己的想法记录下,一来加深自己理解,巩固自己记忆,而来帮助一些想要学习python的朋友理解这门抽象的语言,由于Python是动态语言, ...
最新文章
- 初探Django2.1:Win10+Python3.6.6环境下安装Django
- 环境微生物期刊—Bioresource Technology
- STM32 基础系列教程 42 - SDMMC+Fatfs
- halcon的算子清点: Chapter 2-3-4 控制、开发、文件操作
- Spring Cloud Alibaba:Sentinel实现熔断与限流
- 在SAP UI5应用里使用jQuery.ajax读取数据并显示在页面上
- matlab谐波仿真代码,matlab的谐波仿真程序基于ip-iq法???怎么出不来图像啊???...
- 截取地址栏URL参数
- Linux 系统如何调整时区和时间
- 注册表改win 7更新服务器,Win7 SP1 修改注册表升级的说明事项
- OpenShift 4 - Pod是如何使用Serivce Account访问API的
- MySQL二进制版本的安装及卸载
- DS博客作业03--栈和队列
- 【转】测试用例编写(功能测试框架)
- 综述 | 知识图谱技术综述(下)
- namenode 优化 mv慢的问题
- java array和数组_Java:数组和Arrays类的使用
- 225.队列实现栈 (力扣leetcode) 博主可答疑该问题
- 【定量分析、量化金融与统计学】统计推断基础 番外(3)---假设检验例题讲解
- unix 增强工具_适用于任何UNIX系统的10种出色工具