C#新变量还是引用?

时间:2016-07-11 18:34:22

标签: c#

public class Price
{
  public string Symbol {get; set; }
  public double AskPrice{get; set; }
  public double BidPrice{get; set; }
  public string Exchange{get; set; }
}

public class inputs 
{
  public IList<Price> Prices {get; set; }
}

var inputs = new 
{
Prices = prices,
};

Price[] p = inputs.Prices.Where(x => x.Exchange == exchange).ToArray();

p.ForEach(x => x.AskPrice = 0);

对于这段代码,当我创建新变量p时,它实际上是对input.price的引用,而不是新变量。为什么是这样?有没有关于如何处理这种行为的最佳做法?

2 个答案:

答案 0 :(得分:2)

您没有对p进行更改,p保持不变,您更改了 p 内部元素的内容p内的元素在p和原始来源之间共享。

要获得此行为,您需要在创建新数组时“Deep copy”对象,为具有与原始数据相同内容的元素创建新对象。

public class Price
{
  public string Symbol {get; set; }
  public double AskPrice{get; set; }
  public double BidPrice{get; set; }
  public string Exchange{get; set; }

  public Price Clone()
  {
    var result = new Price();
    result.Symbol = this.Symbol;
    result.AskPrice = this.AskPrice;
    result.BidPrice = this.BidPrice;
    result.Exchange = this.Exchange;
    return result;
  }
}

public class inputs 
{
  public IList<Price> Prices {get; set; }
}

var inputs = new 
{
Prices = prices,
};

Price[] p = inputs.Prices.Where(x => x.Exchange == exchange).Select(x=> x.Clone()).ToArray();

p.ForEach(x => x.AskPrice = 0);

注意,如果您的类中有任何引用类型,则需要递归克隆整个数据结构,并且还需要复制它们。

答案 1 :(得分:1)

这里有两个不同的变量 - 第一个是Price个对象,第二个是input.Prices,它是一个价格列表。

您的LINQ代码采用inputs.Prices列表,过滤它并从中创建一个新数组,但所有这一切都是创建新的集合。它不会更改集合中的实际对象。这是因为C#中的类都是引用类型,这意味着var price = input.Prices[0]只是将引用复制到内存中的单个特定实例。您可以在十几个列表和数组之间复制这些引用,但对象是相同的。

似乎您想要的是克隆按值复制您的Price个对象。为此,您有两种选择:

  1. 使Price成为结构。
  2. 与类不同,结构是值类型并且是按值复制的,这意味着只要将其分配给新变量,就会生成新副本。然而,这会带来性能损失,因为整个结构在每次分配时都会被复制。你的结构占用24-32个字节(两个64位double s和两个32/64位引用string s),这超过了建议的经验法则#34;不超过结构和#34;的16个字节,所以它可能是一个坏主意。

    1. 制作Clone方法。
    2. 让您的Price实现一个返回对象副本的Clone方法 - 或者,创建一个使用旧值创建新Price的复制构造函数。在LINQ中使用它:

      public class Price 
      {
          // your fields
      
         public Price Clone()
         {
             return new Price
             {
                 Symbol = this.Symbol,
                 BidPrice = this.BidPrice,
                 //etc.
             }
         }
      }
      
      var p = input.Prices.Where(x => x.Exchange == exchange).Select(x => x.Clone()).ToArray();