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的引用,而不是新变量。为什么是这样?有没有关于如何处理这种行为的最佳做法?
答案 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
个对象。为此,您有两种选择:
Price
成为结构。与类不同,结构是值类型并且是按值复制的,这意味着只要将其分配给新变量,就会生成新副本。然而,这会带来性能损失,因为整个结构在每次分配时都会被复制。你的结构占用24-32个字节(两个64位double
s和两个32/64位引用string
s),这超过了建议的经验法则#34;不超过结构和#34;的16个字节,所以它可能是一个坏主意。
Clone
方法。让您的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();