详解C#中的属性和属性的使用
作者:goldensun 发布时间:2023-12-03 09:51:39
属性
属性是一种成员,它提供灵活的机制来读取、写入或计算私有字段的值。属性可用作公共数据成员,但它们实际上是称为“访问器”的特殊方法。这使得可以轻松访问数据,还有助于提高方法的安全性和灵活性。
在此示例中,TimePeriod 类存储时间段。该类在内部以秒为单位存储时间,但是名为 Hours 的属性允许客户端以小时为单位指定时间。 Hours 属性的访问器执行小时与秒之间的转换。
class TimePeriod
{
private double seconds;
public double Hours
{
get { return seconds / 3600; }
set { seconds = value * 3600; }
}
}
class Program
{
static void Main()
{
TimePeriod t = new TimePeriod();
// Assigning the Hours property causes the 'set' accessor to be called.
t.Hours = 24;
// Evaluating the Hours property causes the 'get' accessor to be called.
System.Console.WriteLine("Time in hours: " + t.Hours);
}
}
输出:
Time in hours: 24
表达式主体定义
直接只返回表达式结果的属性很常见。下面的语法快捷方式使用 => 来定义这些属性:
public string Name => First + " " + Last;
属性必须为只读,并且你不能使用 get 访问器关键字。
使用属性
属性结合了字段和方法的多个方面。对于对象的用户,属性显示为字段,访问该属性需要相同的语法。对于类的实现者,属性是一个或两个代码块,表示一个 get 访问器和/或一个 set 访问器。当读取属性时,执行 get 访问器的代码块;当向属性分配一个新值时,执行 set 访问器的代码块。不具有 set 访问器的属性被视为只读属性。不具有 get 访问器的属性被视为只写属性。同时具有这两个访问器的属性是读写属性。
属性具有多种用法:它们可在允许更改前验证数据;它们可透明地公开某个类上的数据,该类的数据实际上是从其他源(例如数据库)检索到的;当数据被更改时,它们可采取行动,例如引发事件或更改其他字段的值。
属性在类块中是按以下方式来声明的:指定字段的访问级别,接下来指定属性的类型和名称,然后跟上声明 get 访问器和/或 set 访问器的代码块。例如:
public class Date
{
private int month = 7; // Backing store
public int Month
{
get
{
return month;
}
set
{
if ((value > 0) && (value < 13))
{
month = value;
}
}
}
}
在此示例中,Month 是作为属性声明的,这样 set 访问器可确保 Month 值设置为 1 和 12 之间。 Month 属性使用私有字段来跟踪该实际值。属性的数据的真实位置经常称为属性的“后备存储”。属性使用作为后备存储的私有字段是很常见的。将字段标记为私有可确保该字段只能通过调用属性来更改。
。
get 访问器
get 访问器体与方法体相似。它必须返回属性类型的值。执行 get 访问器相当于读取字段的值。例如,当正在从 get 访问器返回私有变量并且启用了优化时,对 get 访问器方法的调用由编译器进行内联,因此不存在方法调用的系统开销。然而,由于在编译时编译器不知道在运行时实际调用哪个方法,因此无法内联虚拟 get 访问器。以下是返回私有字段 name 的值的 get 访问器:
class Person
{
private string name; // the name field
public string Name // the Name property
{
get
{
return name;
}
}
}
当引用属性时,除非该属性为赋值目标,否则将调用 get 访问器以读取该属性的值。例如:
Person person = new Person();
//...
System.Console.Write(person.Name); // the get accessor is invoked here
get 访问器必须以 return 或 throw 语句终止,并且控制权不能离开访问器体。
通过使用 get 访问器更改对象的状态不是一种好的编程风格。例如,以下访问器在每次访问 number 字段时都会产生更改对象状态的副作用。
private int number;
public int Number
{
get
{
return number++; // Don't do this
}
}
get 访问器可用于返回字段值,或用于计算并返回字段值。例如:
class Employee
{
private string name;
public string Name
{
get
{
return name != null ? name : "NA";
}
}
}
在上一个代码段中,如果不对 Name 属性赋值,它将返回值 NA。
set 访问器
set 访问器类似于返回类型为 void 的方法。它使用称为 value 的隐式参数,此参数的类型是属性的类型。在下面的示例中,将 set 访问器添加到 Name 属性:
class Person
{
private string name; // the name field
public string Name // the Name property
{
get
{
return name;
}
set
{
name = value;
}
}
}
当对属性赋值时,用提供新值的参数调用 set 访问器。例如:
Person person = new Person();
person.Name = "Joe"; // the set accessor is invoked here
System.Console.Write(person.Name); // the get accessor is invoked here
在 set 访问器中,对局部变量声明使用隐式参数名称 value 是错误的。
此例说明了实例、静态和只读属性。它从键盘接受雇员的姓名,按 1 递增 NumberOfEmployees,并显示雇员的姓名和编号。
public class Employee
{
public static int NumberOfEmployees;
private static int counter;
private string name;
// A read-write instance property:
public string Name
{
get { return name; }
set { name = value; }
}
// A read-only static property:
public static int Counter
{
get { return counter; }
}
// A Constructor:
public Employee()
{
// Calculate the employee's number:
counter = ++counter + NumberOfEmployees;
}
}
class TestEmployee
{
static void Main()
{
Employee.NumberOfEmployees = 107;
Employee e1 = new Employee();
e1.Name = "Claude Vige";
System.Console.WriteLine("Employee number: {0}", Employee.Counter);
System.Console.WriteLine("Employee name: {0}", e1.Name);
}
}
输出:
Employee number: 108
Employee name: Claude Vige
此示例说明如何访问基类中由派生类中具有同一名称的另一个属性所隐藏的属性。
public class Employee
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
public class Manager : Employee
{
private string name;
// Notice the use of the new modifier:
public new string Name
{
get { return name; }
set { name = value + ", Manager"; }
}
}
class TestHiding
{
static void Main()
{
Manager m1 = new Manager();
// Derived class property.
m1.Name = "John";
// Base class property.
((Employee)m1).Name = "Mary";
System.Console.WriteLine("Name in the derived class is: {0}", m1.Name);
System.Console.WriteLine("Name in the base class is: {0}", ((Employee)m1).Name);
}
}
输出:
Name in the derived class is: John, Manager
Name in the base class is: Mary
以下是上一个示例中的要点:
派生类中的属性 Name 隐藏基类中的属性 Name。在这种情况下,派生类的属性声明中使用 new 修饰符:
public new string Name
转换 (Employee) 用于访问基类中的隐藏属性:
((Employee)m1).Name = "Mary";
在此例中,Cube 和 Square 这两个类实现抽象类 Shape,并重写它的抽象 Area 属性。注意属性上 override 修饰符的使用。程序接受输入的边长并计算正方形和立方体的面积。它还接受输入的面积并计算正方形和立方体的相应边长。
abstract class Shape
{
public abstract double Area
{
get;
set;
}
}
class Square : Shape
{
public double side;
public Square(double s) //constructor
{
side = s;
}
public override double Area
{
get
{
return side * side;
}
set
{
side = System.Math.Sqrt(value);
}
}
}
class Cube : Shape
{
public double side;
public Cube(double s)
{
side = s;
}
public override double Area
{
get
{
return 6 * side * side;
}
set
{
side = System.Math.Sqrt(value / 6);
}
}
}
class TestShapes
{
static void Main()
{
// Input the side:
System.Console.Write("Enter the side: ");
double side = double.Parse(System.Console.ReadLine());
// Compute the areas:
Square s = new Square(side);
Cube c = new Cube(side);
// Display the results:
System.Console.WriteLine("Area of the square = {0:F2}", s.Area);
System.Console.WriteLine("Area of the cube = {0:F2}", c.Area);
System.Console.WriteLine();
// Input the area:
System.Console.Write("Enter the area: ");
double area = double.Parse(System.Console.ReadLine());
// Compute the sides:
s.Area = area;
c.Area = area;
// Display the results:
System.Console.WriteLine("Side of the square = {0:F2}", s.side);
System.Console.WriteLine("Side of the cube = {0:F2}", c.side);
}
}
输出:
Enter the side: 4
Area of the square = 16.00
Area of the cube = 96.00
Enter the area: 24
Side of the square = 4.90
Side of the cube = 2.00


猜你喜欢
- 启动命令:java -jar weichi-1.0.0.jar将命令打印到1.log上 java -jar weichi-1.0.0.jar
- 可能也有其他方法,比如用 WGet 等等,但是 推荐用 PowerShell ,为什么呢,因为 PowerShell 太强大呗PowerSh
- 关于在Android中实现ListView的弹性效果,有很多不同的方法,网上一搜,也有很多,下面贴出在项目中经常用到的两种实现ListVie
- Semaphore、SemaphoreSlim 类两者都可以限制同时访问某一资源或资源池的线程数。这里先不扯理论,我们从案例入手,通过示例代
- 文件上传的方法主要目前有两个常用的,一个是SmartUpload,一个是Apache的Commons fileupload.我们这里主要介绍
- 前言最近在学习Android开发,发现确实有太多东西需要去整理,去学习。慢慢来吧,任何东东的深入学习都是不简单的。今天稍微整理下Spanna
- 在C#中,@符号不仅可以加在字符串常量之前,使字符串不作转义之用,还可以加在变量名之前,使变量名与关键字不冲突,这种用法称为“逐字标识符”。
- ProgressBar进度条,分为旋转进度条和水平进度条,进度条的样式根据需要自定义,之前一直不明白进度条如何在实际项目中使用,网上演示进度
- 本文实例为大家分享了Android Scroller的使用方法,供大家参考,具体内容如下1、scrollTo和ScrollByView类定义
- 建造者模式概述建造者模式(Builder Pattern)属于创建型模式。它是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同
- SpringAOP的介绍:传送门demo介绍主要通过自定义注解,使用SpringAOP的环绕通知拦截请求,判断该方法是否有自定义注解,然后判
- Java9 集合类扩展of方法package com.jd.collections;import org.junit.Test;import
- 对于步入编程行业不深的初学者或是已经有所领会的人来说,当学习一项新的技术的时候,非常渴望有一个附上注释完整的Demo。本人深有体会,网上的例
- 本文实例为大家分享了Android登录注册功能的具体代码,供大家参考,具体内容如下展示效果代码区MainActivity(登录方法)publ
- strings.xml 有很多需要注意的地方和一些小技巧,知道了这些可以让你的 Android 应用更加规范易用,感兴趣的小伙伴们可以参考一
- 这几天在项目里面发现我使用@Transactional注解事务之后,抛了异常居然不回滚。后来终于找到了原因。如果你也出现了这种情况,可以从下
- Netty是一个非常优秀的Socket框架。如果需要在SpringBoot开发的app中,提供Socket服务,那么Netty是不错的选择。
- 本文实例为大家分享了Android登录邮箱自动补全功能的实现方法,供大家参考,具体内容如下效果:实现原理:1、继承重写简单控件AutoCom
- 方法一、利用控件或窗体的Paint事件中的PainEventArgs在窗体或控件的Paint事件中接收对图形对象的引用,作为PaintEve
- 原理解析:利用RandomAccessFile在本地创建一个随机访问文件,文件大小和服务器要下载的文件大小相同。 根据线程的数量(假设有三个