可以在 C# 中将变量的引用保存在另一个变量中吗?
It is possible to save a variable's reference inside another variable in c#?
我正在开发一款小型主机游戏,您可以在其中穿越地牢。我正在尝试为它制作一个药水系统,想法是当你使用药水时,它会改变玩家的特定属性。
玩家的统计数据存储在名为 Stats
的静态 class 中。我想从相同的 class 创建不同的药水,并使用其构造方法更改药水作用的统计数据。我希望它工作的方式是,当创建一个新的药水实例时,我将对 stat 变量的引用传递给构造函数,并且构造函数将该引用存储在一个变量中,以便在使用药水时使用它。
我尝试将 delegates 与 getter 和 setter 一起使用,但它不起作用,因为它们仅适用于函数。我可以通过制作药水 ID 系统或学习正确使用指针来解决这个问题,但我更喜欢只使用安全代码。
我的问题是:在c#中有一种方法可以将对一个变量的引用存储在另一个变量中吗?
Stats
class:
static class Stats{
public static int health = 10,
strenght = 5,
defense = 20;
}
药水class:
class Potion {
int statRef; //This is the "reference holder" variable I was asking about.
int magnitude;
public Potion(ref int stat, int _magnitude)
{
magnitude = _magnitude;
statRef = stat; //Here I want to save the reference to the stat to the "reference holder"
}
public void UsePotion()
{
statRef += magnitude; //Here I want to change the referenced variable's value.
}
}
主程序:
class Program{
static class Main(string[] args)
{
Potion lifePotion = new Potion(Stats.life, 5);
Potion strenghtPotion = new Potion(Stats.strenght, 5);
Potion defensePotion = new Potion(Stats.defense, 10);
lifePotion.UsePotion();
strenghtPotion.UsePotion();
defensePotion.UsePotion();
Console.WriteLine(Stats.health);
Console.WriteLine(Stats.strenght);
Console.WriteLine(Stats.defense);
}
}
C# 是一种面向对象的编程语言。这意味着它旨在使用“对象”或 classes 的内存实例,它们负责维护自己的状态。现在你不必这样做,但是你越偏离这个设计,语言对你的支持就越少,你自己要做的工作就越多。
你的设计不是面向对象的。可能没有一个“统计数据”在您的游戏中四处游荡,统计数据。它可能也不是 static
。静态 classes 用于无法更改的概念。例如Math.Sin
就是static
;它的意思不能改变,我的 Math.Sin
就是你的 Math.Sin
.
您的游戏可能有角色或 Mook,而不是 static Stats
四处游荡。所以为他们做一个class:
public class Mook
{
public string Name { get; }
public int Strength { get; private set; }
public Mook(string name, int strength)
{
Name = string.IsNullOrWhiteSpace(name) ? throw new ArgumentNullException(nameof(name)) : name;
Strength = strength;
}
}
现在您可以创建 Mooks 的实例:
var player = new Mook("Link", 10);
var monster = new Mook("Orc", 11);
Mooks 可以做一些事情,比如攻击或喝药水。药水可以做一些事情,比如改变你的力量。每个 class 只对自己的内部状态负责;您没有改变 Mooks 的药水,只有 Mook 自己可以做到这一点。 类做一些通过方法改变自己的事情。如果你想让 Mook 喝药水,你必须在你的 Mook 中创建一个方法 class 来做到这一点:
public void Drink(Potion potion)
{
switch (potion.Sipped())
{
case PotionEffect.ModifyStrength:
Strength += potion.Modifier;
break;
}
}
药水无法决定自身之外发生的事情,只有 class 使用药水才能做到。要跟踪药水的可能效果,请创建一个枚举:
public enum PotionEffect
{
Nothing,
ModifyStrength
}
药水是其他物品,所以你需要再制作一个class。请记住,每个 class 负责维护自己的状态:
public class Potion
{
public PotionEffect Effect { get; }
public int Modifier { get; }
public int Doses { get; private set; }
public Potion(PotionEffect defaultEffect, int modifier, int doses)
{
Effect = defaultEffect;
Modifier = modifier;
Doses = doses;
}
public PotionEffect Sipped()
{
if (Doses <= 0)
return PotionEffect.Nothing;
Doses--;
return Effect;
}
}
现在你可以制作药水了:
var strengthPotion = new Potion(PotionEffect.ModifyStrength, +1, 10);
然后让 mooks 喝它们:
player.Drink(strengthPotion);
monster.Drink(strengthPotion);
请注意,class 是引用类型。因此,class 类型的变量自动包含引用,您可以将相同的引用分配给另一个变量。如果 class 不是静态的,您只能创建一个对象(即 class 的实例)。然后你可以把它赋值给一个变量。
字段或属性不能是静态的。非静态成员称为实例成员。每个实例(对象)都有自己的字段和属性副本,必须通过变量名访问这些副本。相反,静态成员在该类型的所有对象之间共享,并且必须通过 class 名称访问。
Stats stats1 = new Stats();
Stats stats2 = stats1;
现在两个变量引用相同的统计数据。如果你做出改变
stats1.health = 5;
then stats2.health
也是 5,因为两者都引用同一个对象。但当然,您可以创建独立的 Stats
个对象:
Stats stats1 = new Stats();
Stats stats2 = new Stats();
现在对 stats1
的更改不会影响 stats2
。
请注意,面向对象编程 (OOP) 的一个重要思想是对象应隐藏其内部状态,即它们的字段。从外部状态只能通过方法访问。这些方法确保以适当的方式操纵状态。例如,可以确保健康保持在有效范围内。
属性是允许操纵字段状态的专用方法。它们通常由一对 get
和 set
方法组成,可以像字段一样访问。
示例:
class Stats
{
private int _health = 10;
public int Health
{
get { // called when reading the value: int h = stats1.Health;
return _health;
}
set { // called when setting the value: stats1.Health = 5;
if (value < 0) {
_health = 0;
} else if (value > 100) {
_health = 100;
} else {
_health = value;
}
}
}
}
如果 属性 没有这样的逻辑,您可以使用自动实现的 属性。它会自动创建一个不可见的支持字段(如 _health
)和 returns 并设置其值。
public int Health { get; set; }
让我们把这些东西放在一起。 Stats
class的简单例子:
class Stats
{
public int Health { get; set; } = 10;
public int Strength { get; set; } = 5;
public int Defense { get; set; } = 20;
}
现在您可以在 Potion
class 中引用 Stats
对象。
因为你想拥有不同种类的药水,你可以使用继承(OOP 的另一个重要概念)来实现。
你可以声明一个抽象基础class,即一个不能被实例化并且本身可以包含抽象成员的class,即仍然需要在派生[=77中定义的成员=]es.
abstract class Potion
{
// This is the "reference holder" variable you were asking about.
protected Stats _stats;
// Protected means private and visible to derived classes.
protected int _magnitude;
public Potion(Stats stats, int magnitude)
{
_stats = stats; // Save the reference to the stat to the "reference holder"
_magnitude = magnitude;
}
public abstract void UsePotion();
}
现以派生LifePotion
class为例
class LifePotion : Potion // Inherits Potion.
{
public LifePotion(Stats stats, int magnitude)
: base(stats, magnitude) // Calls the base constructor.
{
}
public override void UsePotion()
{
_stats.Health += _magnitude; // Change a property of the referenced variable.
}
}
对 StrenghtPotion
和 DefensePotion
class 重复相同的操作,UsePotion
设置 Strength
和 Defense
属性。
适配主程序
class Program{
static class Main(string[] args)
{
var stats = new Stats();
Potion lifePotion = new LifePotion(stats, 5);
Potion strenghtPotion = new StrengthPotion(stats, 5);
Potion defensePotion = new DefensePotion(stats, 10);
lifePotion.UsePotion();
strenghtPotion.UsePotion();
defensePotion.UsePotion();
Console.WriteLine(stats.Health);
Console.WriteLine(stats.Strength);
Console.WriteLine(stats.Defense);
}
}
请注意,您可以在 class 中覆盖 ToString
并提供您自己的实现。将此添加到 Stats
class:
public override string ToString()
{
return $"Health = {Health}, Strength = {Strength}, Defense = {Defense}";
}
然后你可以在主例程中像这样打印健康:
Console.WriteLine(stats); // Prints: Health = 15, Strength = 10, Defense = 30
我正在开发一款小型主机游戏,您可以在其中穿越地牢。我正在尝试为它制作一个药水系统,想法是当你使用药水时,它会改变玩家的特定属性。
玩家的统计数据存储在名为 Stats
的静态 class 中。我想从相同的 class 创建不同的药水,并使用其构造方法更改药水作用的统计数据。我希望它工作的方式是,当创建一个新的药水实例时,我将对 stat 变量的引用传递给构造函数,并且构造函数将该引用存储在一个变量中,以便在使用药水时使用它。
我尝试将 delegates 与 getter 和 setter 一起使用,但它不起作用,因为它们仅适用于函数。我可以通过制作药水 ID 系统或学习正确使用指针来解决这个问题,但我更喜欢只使用安全代码。
我的问题是:在c#中有一种方法可以将对一个变量的引用存储在另一个变量中吗?
Stats
class:
static class Stats{
public static int health = 10,
strenght = 5,
defense = 20;
}
药水class:
class Potion {
int statRef; //This is the "reference holder" variable I was asking about.
int magnitude;
public Potion(ref int stat, int _magnitude)
{
magnitude = _magnitude;
statRef = stat; //Here I want to save the reference to the stat to the "reference holder"
}
public void UsePotion()
{
statRef += magnitude; //Here I want to change the referenced variable's value.
}
}
主程序:
class Program{
static class Main(string[] args)
{
Potion lifePotion = new Potion(Stats.life, 5);
Potion strenghtPotion = new Potion(Stats.strenght, 5);
Potion defensePotion = new Potion(Stats.defense, 10);
lifePotion.UsePotion();
strenghtPotion.UsePotion();
defensePotion.UsePotion();
Console.WriteLine(Stats.health);
Console.WriteLine(Stats.strenght);
Console.WriteLine(Stats.defense);
}
}
C# 是一种面向对象的编程语言。这意味着它旨在使用“对象”或 classes 的内存实例,它们负责维护自己的状态。现在你不必这样做,但是你越偏离这个设计,语言对你的支持就越少,你自己要做的工作就越多。
你的设计不是面向对象的。可能没有一个“统计数据”在您的游戏中四处游荡,统计数据。它可能也不是 static
。静态 classes 用于无法更改的概念。例如Math.Sin
就是static
;它的意思不能改变,我的 Math.Sin
就是你的 Math.Sin
.
您的游戏可能有角色或 Mook,而不是 static Stats
四处游荡。所以为他们做一个class:
public class Mook
{
public string Name { get; }
public int Strength { get; private set; }
public Mook(string name, int strength)
{
Name = string.IsNullOrWhiteSpace(name) ? throw new ArgumentNullException(nameof(name)) : name;
Strength = strength;
}
}
现在您可以创建 Mooks 的实例:
var player = new Mook("Link", 10);
var monster = new Mook("Orc", 11);
Mooks 可以做一些事情,比如攻击或喝药水。药水可以做一些事情,比如改变你的力量。每个 class 只对自己的内部状态负责;您没有改变 Mooks 的药水,只有 Mook 自己可以做到这一点。 类做一些通过方法改变自己的事情。如果你想让 Mook 喝药水,你必须在你的 Mook 中创建一个方法 class 来做到这一点:
public void Drink(Potion potion)
{
switch (potion.Sipped())
{
case PotionEffect.ModifyStrength:
Strength += potion.Modifier;
break;
}
}
药水无法决定自身之外发生的事情,只有 class 使用药水才能做到。要跟踪药水的可能效果,请创建一个枚举:
public enum PotionEffect
{
Nothing,
ModifyStrength
}
药水是其他物品,所以你需要再制作一个class。请记住,每个 class 负责维护自己的状态:
public class Potion
{
public PotionEffect Effect { get; }
public int Modifier { get; }
public int Doses { get; private set; }
public Potion(PotionEffect defaultEffect, int modifier, int doses)
{
Effect = defaultEffect;
Modifier = modifier;
Doses = doses;
}
public PotionEffect Sipped()
{
if (Doses <= 0)
return PotionEffect.Nothing;
Doses--;
return Effect;
}
}
现在你可以制作药水了:
var strengthPotion = new Potion(PotionEffect.ModifyStrength, +1, 10);
然后让 mooks 喝它们:
player.Drink(strengthPotion);
monster.Drink(strengthPotion);
请注意,class 是引用类型。因此,class 类型的变量自动包含引用,您可以将相同的引用分配给另一个变量。如果 class 不是静态的,您只能创建一个对象(即 class 的实例)。然后你可以把它赋值给一个变量。
字段或属性不能是静态的。非静态成员称为实例成员。每个实例(对象)都有自己的字段和属性副本,必须通过变量名访问这些副本。相反,静态成员在该类型的所有对象之间共享,并且必须通过 class 名称访问。
Stats stats1 = new Stats();
Stats stats2 = stats1;
现在两个变量引用相同的统计数据。如果你做出改变
stats1.health = 5;
then stats2.health
也是 5,因为两者都引用同一个对象。但当然,您可以创建独立的 Stats
个对象:
Stats stats1 = new Stats();
Stats stats2 = new Stats();
现在对 stats1
的更改不会影响 stats2
。
请注意,面向对象编程 (OOP) 的一个重要思想是对象应隐藏其内部状态,即它们的字段。从外部状态只能通过方法访问。这些方法确保以适当的方式操纵状态。例如,可以确保健康保持在有效范围内。
属性是允许操纵字段状态的专用方法。它们通常由一对 get
和 set
方法组成,可以像字段一样访问。
示例:
class Stats
{
private int _health = 10;
public int Health
{
get { // called when reading the value: int h = stats1.Health;
return _health;
}
set { // called when setting the value: stats1.Health = 5;
if (value < 0) {
_health = 0;
} else if (value > 100) {
_health = 100;
} else {
_health = value;
}
}
}
}
如果 属性 没有这样的逻辑,您可以使用自动实现的 属性。它会自动创建一个不可见的支持字段(如 _health
)和 returns 并设置其值。
public int Health { get; set; }
让我们把这些东西放在一起。 Stats
class的简单例子:
class Stats
{
public int Health { get; set; } = 10;
public int Strength { get; set; } = 5;
public int Defense { get; set; } = 20;
}
现在您可以在 Potion
class 中引用 Stats
对象。
因为你想拥有不同种类的药水,你可以使用继承(OOP 的另一个重要概念)来实现。
你可以声明一个抽象基础class,即一个不能被实例化并且本身可以包含抽象成员的class,即仍然需要在派生[=77中定义的成员=]es.
abstract class Potion
{
// This is the "reference holder" variable you were asking about.
protected Stats _stats;
// Protected means private and visible to derived classes.
protected int _magnitude;
public Potion(Stats stats, int magnitude)
{
_stats = stats; // Save the reference to the stat to the "reference holder"
_magnitude = magnitude;
}
public abstract void UsePotion();
}
现以派生LifePotion
class为例
class LifePotion : Potion // Inherits Potion.
{
public LifePotion(Stats stats, int magnitude)
: base(stats, magnitude) // Calls the base constructor.
{
}
public override void UsePotion()
{
_stats.Health += _magnitude; // Change a property of the referenced variable.
}
}
对 StrenghtPotion
和 DefensePotion
class 重复相同的操作,UsePotion
设置 Strength
和 Defense
属性。
适配主程序
class Program{
static class Main(string[] args)
{
var stats = new Stats();
Potion lifePotion = new LifePotion(stats, 5);
Potion strenghtPotion = new StrengthPotion(stats, 5);
Potion defensePotion = new DefensePotion(stats, 10);
lifePotion.UsePotion();
strenghtPotion.UsePotion();
defensePotion.UsePotion();
Console.WriteLine(stats.Health);
Console.WriteLine(stats.Strength);
Console.WriteLine(stats.Defense);
}
}
请注意,您可以在 class 中覆盖 ToString
并提供您自己的实现。将此添加到 Stats
class:
public override string ToString()
{
return $"Health = {Health}, Strength = {Strength}, Defense = {Defense}";
}
然后你可以在主例程中像这样打印健康:
Console.WriteLine(stats); // Prints: Health = 15, Strength = 10, Defense = 30