前言
我们先前介绍了类中的构造函数,并且了解了一下析构以及垃圾回收,简单对c#底层的内存处理机制做了一定了解,现在我们要介绍一个新的东西,叫成员属性。
成员属性和成员变量有什么区别呢?
成员属性(Property)和成员变量(Field)是 C# 中两种不同的结构,用于封装与对象相关的数据。它们各自有不同的目的和使用方式。
成员变量
定义:成员变量是类或结构体内部的字段,用于直接存储数据。成员变量通常是私有的(使用`private`修饰符),从而遵循封装原则。
访问性:成员变量通常不直接对外部代码公开,建议通过属性进行访问。直接访问成员变量可能导致数据不一致或有效性问题。
public class Person
{
private string name; // 成员变量
}
成员属性
定义:成员属性是对成员变量的封装,它提供了一种通过`get`和`set`访问器来访问和操作成员变量的方法。使用属性可以添加逻辑验证、数据转换等功能。
访问性:成员属性可以是公共的,使外部代码能够安全地访问或修改对象的数据。属性可以实现只读(只有`get`)或只写(只有`set`)的访问。
public class Person
{
private string name; // 成员变量
public string Name // 成员属性
{
get { return name; }
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Name cannot be empty.");
}
name = value;
}
}
}
这样解释起来你可能觉得还是有一点抽象,那这么说吧,它属于更为详细的变量,在使用它的时候我们可以默认使用一些操作。
具体是什么情况,我们在接下来的文章进行更详细的讲解。
基本概念
- 是用来保护成员变量的
- 为成员属性的获取和逻辑赋值添加而存在
- 解决3p(public,private,protected)的局限性(比如有些private变量我们在传入的时候其实也是希望对其进行一定的修改的)
你看到这个依旧会觉得很抽象,那我们就来看基础语法进行更详细地讲解。
基本语法
访问修饰符 属性类型 属性名(一般用帕斯卡命名法,因为本质上是变量)
{
get{}
set{}
}
//例子
public string Name
{
get
{
//可以在返回之前加一些逻辑规则
return name;
}
set
{
//可以在设置之前加一些逻辑规则
//value 关键字,用来表示外部传入进来的值
name=value;
}
}
看起来还是很抽象对吧,name是什么?Name又是什么?这样说吧,Name是对name的赋值进行控制操作。
我们来看个例子吧
例子
public class Person
{
private string name;
public string Name
{
get
{
return name ?? "Default Name"; // 如果name是null,则返回默认值
}
set
{
if (string.IsNullOrWhiteSpace(value)) //读英文或者查文档
{
throw new ArgumentException("不能为空或者无效");
}
name = value;
}
}
}
//使用
class Program
{
static void Main(string[] args)
{
// 创建Person类的实例
Person person = new Person();
// 设置Name属性
try
{
person.Name = "Alice"; // 赋值给Name属性
Console.WriteLine(person.Name); // 获取并输出Name属性的值
}
catch (ArgumentException ex)
{
Console.WriteLine(ex.Message); // 输出异常信息
}
// 设置一个无效的Name
try
{
person.Name = ""; // 试图设置为空字符串
}
catch (ArgumentException ex)
{
Console.WriteLine(ex.Message); // 输出异常信息
}
// 获取Name属性(如果设置成功)
Console.WriteLine(person.Name); // 输出: Alice
// 如果name为null,返回默认值
Person person2 = new Person();
Console.WriteLine(person2.Name); // 输出: Default Name
}
}
通过这个例子,我们也能很好get到成员属性存在的意义。
get和set
我们来解释一下get和set吧。
赋值 | set(可以用于游戏相关数据的加密) |
调用 | get(可以用于游戏相关数据的解密) |
表格中的解释其实也是给了我们一些在游戏种使用二者的原因,比如反外挂,有些数值我们就可以通过一些公式加密解密,让一些外挂不能暴力修改数值达到目的
当然,其实你也可以在这里面做一些基本的逻辑操作,这里博主就不多加解释了。
get,set前可以加访问修饰符
- 默认不加,会使用属性申明时的访问权限,也就是成员属性的访问权限决定了get和set的默认权限
- 加的访问修饰符要低于成员属性的访问修饰符
- 不能让get和set的访问修饰符都低于属性权限
解释:如果get和set方法的访问修饰符都低于属性权限,那么外部代码就可以直接访问属性的值,绕过了set方法的校验和控制。这样就容易破坏属性的封装性和安全性,导致类的数据不可靠。
get和set可以只有一个
也就是只得不改(比如有些默认的东西,玩家的跳跃高度,我们就只希望在外面得到使用,但是我们并不需要去动他),或者只改不得(比如游戏的版本号,我们只用在用户安装的一瞬间修改就行了,后续就不用继续修改了)。
tips:只有一个时,没必要在前面加访问修饰符,一般情况只会出现只有get的情况,也就是只得不改。
自动属性
作用:外部能得不能改的时候,而且又没什么特殊处理,那么直接使用自动属性。
例子:
以下是博主用c#实现的一个角色示例,里面包括了以上的所有知识点,包括访问修饰符的权限,以及自动属性,大家可以试着敲一敲,来更好地理解成员属性的作用,博主尽量写了注释,方便你更好理解成员属性。
public class Character
{
// 私有字段
private string characterId; // 角色的唯一标识符
private string name; // 角色名字
private int level; // 角色等级
private int health; // 角色的健康值
// 只读属性:角色唯一标识符,外部无法修改
public string CharacterId
{
get { return characterId; }
}
// 公共属性:名字,允许外部读取和修改
public string Name
{
get { return name; }
set { name = value; } // 外部可以修改名字
}
// 公共属性:等级,允许外部读取和修改,包含逻辑来限制合法值
public int Level
{
get { return level; }
set
{
// 应用简单的限制,等级必须在1到100之间
if (value < 1)
{
level = 1;
}
else if (value > 100)
{
level = 100;
}
else
{
level = value;
}
}
}
// 只读属性:健康值,只能由内部逻辑修改
public int Health
{
get { return health; }
private set { health = value; } // 外部无法修改健康值
}
// 自动属性:魔力值
public int Magic { get; set; } // 默认访问修饰符为 public
// 构造函数,初始化角色属性
public Character(string characterId, string name, int level, int health, int magic)
{
this.characterId = characterId;
this.name = name;
this.Level = level; // 使用属性,由于有验证逻辑
this.Health = health; // 初始化健康值
this.Magic = magic; // 初始化魔力值
}
// 方法:角色受到伤害
public void TakeDamage(int damage)
{
Health -= damage; // 减少健康值
if (Health < 0)
{
Health = 0; // 确保健康值不低于0
}
}
}
class Program
{
static void Main(string[] args)
{
// 创建 Character 对象
Character character = new Character("C001", "Knight", 1, 100, 50);
// 打印角色信息
Console.WriteLine($"Character ID: {character.CharacterId}");
Console.WriteLine($"Name: {character.Name}, Level: {character.Level}, Health: {character.Health}, Magic: {character.Magic}");
// 升级角色
character.Level = 10;
Console.WriteLine($"After leveling up: {character.Name} is now level {character.Level}");
// 角色受到伤害
character.TakeDamage(30);
Console.WriteLine($"{character.Name} took damage! Current Health: {character.Health}");
// 尝试修改 CharacterId 会导致编译错误
// character.CharacterId = "C002"; // Uncommenting this line will cause a compile-time error
// 修改角色的名字
character.Name = "Heroic Knight";
Console.WriteLine($"Updated Name: {character.Name}");
// 修改魔力值
character.Magic = 75;
Console.WriteLine($"Updated Magic: {character.Magic}");
}
}
总结
核心的知识都普遍比较干,大家一定要耐心敲代码,然后耐心学习,切记浮躁,你现在确实可以写一些简单游戏了,但是你如果想写出令自己满意的游戏,令玩家满意的游戏,路还很长,这些基础相当重要,也是你未来的基石。
请期待我的下一篇文章,请务必将我给出的例子自己实现后消化理解,这些东西在日后的使用也是格外频繁的。
我来自佑梦游戏开发,欢迎你的关注和订阅!