我目前正在使用 Unity3D 引擎使用 C# 并遇到以下问题:
我创建了一个类,它有两个对它必须访问的另一个类的实例的私有引用。一旦我创建了类的多个实例并设置了引用,我发现所有实例都使用相同的变量。我在销毁一个实例时意识到了这一点,并且在此之前将两个持有引用的变量设置为空。这样做之后,所有其他实例都立即抛出 NullReferenceExceptions,因为它们仍在尝试访问引用。引用的对象很好,其他脚本仍然可以访问它们。
这是一些说明结构的伪代码:
public class Character
{
// Character data
}
public class StatusEffect
{
private Character target;
private Character originator;
public void Init(Character _Target, Character _Originator)
{
target = _Target;
originator = _Originator;
}
public void Destroy()
{
target = null;
originator = null;
}
}
在程序中它会被这样调用:
StatusEffect effect = new StatusEffect();
effect.Init(player1, player2);
// Time goes by
effect.Destroy();
在调用 Destroy() 之后,每个 StatusEffect 的两个引用都将为空。
这不仅是销毁 StatusEffects 时的问题,而且在创建新的时也是如此。一旦我从一个新实例中触摸引用,所有 StatusEffects 将引用由新 StatusEffect 指定的两个字符。
我不明白为什么或如何解决这个问题。有人可以在这件事上启发我吗?
干杯,瓦尔塔罗斯
编辑:
这是所要求的真实代码:我有一个包含多个 StatusEffects 的容器类。一旦启动,它就会初始化所有这些。
public class CElementTag
{
// ..Other data..
public float f_Duration; // Set in the editor
private CGladiator gl_target;
private CGladiator gl_originator;
private float f_currentDuration;
public CStatusEffect[] ar_statusEffects;
// Starts the effect of the element tag
public void StartEffect(CGladiator _Originator, CGladiator _Target)
{
gl_originator = _Originator;
gl_target = _Target;
f_currentDuration = f_Duration;
for(int i = 0; i < ar_statusEffects.Length; i++)
ar_statusEffects[i].Initialize(gl_originator, gl_target);
}
// Ends the effect of the element tag
public void EndEffect()
{
for(int i = 0; i < ar_statusEffects.Length; i++)
{
if(ar_statusEffects[i] != null)
ar_statusEffects[i].Destroy();
}
}
// Called every update, returns true if the tag can be destroyed
public bool ActivateEffect()
{
f_currentDuration -= Time.deltaTime;
if(f_currentDuration <= 0.0f)
{
EndEffect();
return true;
}
for(int i = 0; i < ar_statusEffects.Length; i++)
{
if(ar_statusEffects[i] != null && ar_statusEffects[i].Update())
RemoveStatusEffect(i);
}
return false;
}
// Removes expired status effects
private void RemoveStatusEffect(int _Index)
{
// Call destroy method
ar_statusEffects[_Index].Destroy();
// Remove effect from array
for(int i = _Index; i < ar_statusEffects.Length - 1; i++)
ar_statusEffects[i] = ar_statusEffects[i+1];
ar_statusEffects[ar_statusEffects.Length - 1] = null;
}
}
实际的 StatusEffect 类包含两个引用以及它需要工作的一些其他数据。它有虚方法,因为有一些类继承自它。
public class CStatusEffect
{
// ..Necessary data..
// References
protected CGladiator gl_target;
protected CGladiator gl_originator;
virtual public void Initialize(CGladiator _Target, CGladiator _Originator)
{
gl_target = _Target;
gl_originator = _Originator;
// ..Initialize other necessary stuff..
}
virtual public void Destroy()
{
gl_target = null;
gl_originator = null;
// ..Tidy up other data..
}
virtual public bool Update()
{
// ..Modifying data of gl_target and gl_originator..
// Returns true as soon as the effect is supposed to end.
}
}
这应该是关于这个问题的所有相关代码。
编辑2
@KeithPayne我在编辑器中定义了一个静态元素标签数组并保存到xml。在程序开始时,静态数组正在加载 xml 并存储所有元素标签。在创建要使用的新元素标记时,我使用此构造函数:
// Receives a static tag as parameter
public CElementTag(CElementTag _Tag)
{
i_ID = _Tag.i_ID;
str_Name = _Tag.str_Name;
enum_Type = _Tag.enum_Type;
f_Duration = _Tag.f_Duration;
ar_statusEffects = new CStatusEffect[_Tag.ar_statusEffects.Length];
Array.Copy(_Tag.ar_statusEffects, ar_statusEffects, _Tag.ar_statusEffects.Length);
}
我是否必须使用不同的方法将数组复制到新标签?我认为 Array.Copy 会对源数组进行深层复制并将其存储在目标数组中。如果它实际上是在做一个浅拷贝,我明白问题出在哪里了。