如何防止修改Collection中的对象而不使类型成为结构?

时间:2014-03-13 08:34:13

标签: c# collections struct

采用以下示例代码:

class Program
{
    static void Main( string[] args )
    {
        Stack<Data> s = new Stack<Data>();

        Data d = new Data( 10 );

        s.Push( d );

        d.Value = 20;

        Console.ReadKey();
    }
}

class Data
{
    public int Value;

    public Data( int value )
    {
        Value = value;
    }
}

没有Data struct有什么方法可以阻止d实例放入堆栈,使d.Value = 20更新对象属性线?当d被推入堆栈时,它的Value属性被赋值为10,但是当属性被修改时,它被更改为20。有没有其他方法可以阻止结构或克隆类来阻止它?

我问这个是因为我正在写一个国际象棋引擎,作为搜索和评估的一部分,它需要在棋盘上移动棋子。将电路板放在堆栈上时,我可以创建子分析板,这会影响已经堆叠的电路板。

3 个答案:

答案 0 :(得分:0)

没办法。由于您使用引用类型,它应该更改所有实例。如果您在我建议您使用Object.MemberwiseClone方法之前使用 Value 的简单类型。

<强>更新

这个实现怎么样:

static void Main(string[] args)
{
  Stack<Data> s = new Stack<Data>();

  Data d = new Data(10);
  d.Freeze();

  s.Push(d);

  d.Value = 20;

  Console.WriteLine("Frozen value : {0}", s.Pop().Value);
  Console.WriteLine("actual value : {0}", d.Actual(data => data.Value));
  Console.ReadKey();
}

  class FreezableValue<T>
  {
    private T frozenValue;
    private T actualValue;
    private bool isFrozen;

    public void Freeze()
    {
      isFrozen = true;
    }

    public T ActualValue
    {
      get
      {
        return actualValue;
      }
      set
      {
        this.actualValue = value;
        if(!isFrozen)
          frozenValue = value;
      }
    }

    public T FrozenValue { get { return frozenValue; } }
  }

  class Data
  {
    private readonly FreezableValue<int> freezableValue;
    private bool useActualValue;

    public Data(int value)
    {
      freezableValue = new FreezableValue<int> { ActualValue = value };
      useActualValue = true;
    }

    public void Freeze()
    {
      freezableValue.Freeze();
      useActualValue = false;
    }

    public int Value
    {
      get { return useActualValue ? freezableValue.ActualValue : freezableValue.FrozenValue; }
      set { freezableValue.ActualValue = value; }
    }

    public T Actual<T>(Func<Data, T> func)
    {
      useActualValue = true;
      try
      {
        return func(this);
      }
      finally
      {
        useActualValue = false;
      }
    }
  }

答案 1 :(得分:0)

没有可能的方法将Board类转换为struct因为它太大而且有很多引用类型所以我决定不使用Stack对象来存储国际象棋的实例板。

相反,我创建了一个BoardManager静态类来将所有单独创建的棋盘存储在列表中,当我需要某个板时,我只需使用板的标识符来检索它。

答案 2 :(得分:-1)

您可以使您的类Data实现只读接口:

 public interface IReadOnlyData {

    int SomeInt { get;}
    string SomeString {get;}
}

然后你的Stack可以是:

Stack<IReadOnlyData> stack = new Stack<IReadOnlyData>();