C#所有类实例共享的私有成员

C#所有类实例共享的私有成员,c#,class,reference,unity3d,member,C#,Class,Reference,Unity3d,Member,我目前正在使用Unity3D引擎与C#合作,遇到以下问题: 我创建了一个类,该类有两个私有引用,指向它必须访问的另一个类的实例。创建类的多个实例并设置引用后,我发现所有实例都使用相同的变量。我在销毁一个实例时意识到了这一点,就在这之前,我将保存引用的两个变量设置为null。执行此操作后,所有其他实例立即抛出NullReferenceException,因为它们仍在尝试访问引用。引用的对象很好,其他脚本仍然可以访问它们 下面是一些说明结构的伪代码: public class Character {

我目前正在使用Unity3D引擎与C#合作,遇到以下问题:

我创建了一个类,该类有两个私有引用,指向它必须访问的另一个类的实例。创建类的多个实例并设置引用后,我发现所有实例都使用相同的变量。我在销毁一个实例时意识到了这一点,就在这之前,我将保存引用的两个变量设置为null。执行此操作后,所有其他实例立即抛出NullReferenceException,因为它们仍在尝试访问引用。引用的对象很好,其他脚本仍然可以访问它们

下面是一些说明结构的伪代码:

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的两个引用都将为null

这不仅是销毁状态效果时的问题,也是创建新效果时的问题。只要我从新实例中触摸到引用,所有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;
}
}
这应该是关于这个问题的所有相关规范

EDIT2

@KeithPayne我在编辑器中定义了一个ElementTags静态数组,并保存到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会对源数组进行深度复制,并将其存储在目标数组中。如果它实际上是在进行浅层复制,我理解问题的根源。

这些字段在其他实例中不共享(静态)。所以调用
target=nullDestroy()
中的code>不会影响其他实例

StatusEffect effect1 = new StatusEffect();
effect1.Init(player1, player2);

StatusEffect effect2 = new StatusEffect();
effect2.Init(player1, player2);

// Time goes by

effect2.Destroy();

// Some more time goes by

// accessing effect1.target won't give a `NullReferenceException` here unless player1 was null before passed to the init.

effect1.Destroy();
我想您确实忘记了其他实例上的
Init(..)
。每次创建
StatusEffect
的实例时,都需要调用
Init(…)


更新:

此行将清除对效果的引用,但您永远不会重新创建它:

ar_statusEffects[ar_statusEffects.Length - 1] = null;
因此,下次调用
ar\u statusEffects[x].Update()或Initialize()等时,它将抛出NullReferenceException

如果要清除数组中的
效果,可以在效果中创建
启用
布尔,这样您只需设置/重置它

    for(int i = 0; i < ar_statusEffects.Length; i++)
        if(ar_statusEffects[i].IsEnabled)
            ar_statusEffects[i].Update();
for(int i=0;i

你为什么不用列表来代替呢?只要你不需要洗牌,数组就会更快。(如循环缓冲区等)

因为您是通过
Init()
方法传入对对象的引用,所以实际上并不是“复制”对象,而是在内存中维护对相同底层对象的引用

如果您有多个
播放器
对相同的基础对象具有相同的引用,则播放器1所做的更改将影响播放器2所使用的对象

话虽如此,您实际上并没有在
Destory
方法中处理对象。只需将本地实例引用设置为Null,这不应影响StatusEffects的任何其他实例。您是否确定有其他东西没有处理这些对象,或者您没有正确初始化其他实例

StatusEffect effect1 = new StatusEffect();
effect1.Init(player1, player2);

StatusEffect effect2 = new StatusEffect();
effect2.Init(player1, player2);

// Time goes by

effect2.Destroy();

// Some more time goes by

// accessing effect1.target won't give a `NullReferenceException` here unless player1 was null before passed to the init.

effect1.Destroy();
如果您确实希望获取传入对象的完整副本,请查看IClonable接口。看起来您希望将对象的副本传递给每个玩家

public class Character : ICloneable
{
    // Character data

    //Implement Clone Method
}

public class StatusEffect
{
    private Character target;
    private Character originator;

    public void Init(Character _Target, Character _Originator)
    {
        target = _Target.Clone()
        originator = _Originator.Clone();
    }

多亏了基思·佩恩,我才知道问题出在哪里。我正在创建CElementTag的深层副本,但没有创建ar_statusEffects数组。我错误地假设了数组。Copy正在创建数组的深度副本,而实际上它不是

我为我的CStatusEffect实现了IClonable接口,并使用Clone()方法为静态数组的每个成员创建一个真正的深度副本,并将其添加到新的tags ar_statusEffects数组中。这样我就有了不同的效果实例,而不是对相同静态效果的引用

感谢所有人,特别是基思佩恩,他们的帮助和支持

来自:

如果sourceArray和destinationArray都是引用类型数组或 如果两个数组都是Object类型,则执行浅复制。浅滩 数组的副本是一个新数组,其中包含对该数组的引用 元素作为原始数组。元素本身或任何东西 未复制由图元引用的图元。相比之下,它是 数组直接或间接地复制元素和所有内容 由元素引用

考虑一下这个流畅版本的
StatusEffect
类及其用法:

public class StatusEffect
{
    public Character Target { get; private set; }
    public Character Originator { get; private set; }

    public StatusEffect Init(Character target, Character originator)
    {
        Target = target.Clone()
        Originator = originator.Clone();
        return this;
    }
//...
}    

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 = _Tag.ar_statusEffects.Select(eff => 
            new StatusEffect().Init(eff.Target, eff.Originator)).ToArray();

        // ar_statusEffects = new CStatusEffect[_Tag.ar_statusEffects.Length];
        // Array.Copy(_Tag.ar_statusEffects, ar_statusEffects, _Tag.ar_statusEffects.Length);


    }

你能发布一些代码来演示这个问题吗?根据您的描述和代码示例,您看到的问题是不可能的。另外,您如何确定对象的私有成员都受到影响。@KeithPayne我有每个StatusEffect输出他的目标。当我用一个新的目标创建第二个效果时,第一个效果也会将他的目标更改为新的。仍然可以显示的是
ar\u statusEffect[]
的元素是如何设置的。我怀疑每个数组元素都引用了相同的
CStatusEffect
对象。@KeithPayne我编辑了我的文章,也包括了这个。事实上,它可能已经揭示了我问题的根源。我不知道