【问题标题】:Object reference updating, update all collections property?对象引用更新,更新所有集合属性?
【发布时间】:2017-11-01 10:39:03
【问题描述】:

简介

我发现了一个非常奇怪的情况,所以基本上我有一个名为Matches 的集合属性和一个名为Match 的对象属性。 Matches 集合包含 Match 的项目列表,如下所示:

private ObservableCollection<Match> _matches = new ObservableCollection<Match>(); 
public ObservableCollection<Match> Matches
{
    get { return _matches; }
}

当应用程序启动时,这个集合是有价值的,事实上,软件从一个互联网站点获取一些数据,然后用一个刮刀用相应的对象模型Match填充集合。

错误开始的地方

Matches 集合绑定到 DataGrid。当用户单击DataGrid 上可用的元素(Match)时,代码会触发事件SelectionChanged,在此事件中,我创建了单击的Match 的副本,因此我可以在其中使用此对象我的所有申请:

var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);

正如您使用Linq 所看到的,我检查用户单击的Match 是否与Matches 集合中包含的Match 具有相同的链接,事实上,每个Match 在该集合有一个独特的链接,例如 GUID

错误

Match 对象如下所示:

 private Match _match;
 public Match Match
 {
    get { return _match; }
    set
    {
        _match = value;
        OnPropertyChanged();
    }
 }

正如我所说,它包含用户点击的Match。这个对象允许我从我的应用程序中的所有方法中仅针对这个Match 从 Internet 获取数据。这工作得很好。到现在为止。

我的应用程序允许用户应用一些过滤器,本质上是用户按下一个按钮,然后使用用户填写的属性更新保存的Match,例如:

Match.League.Rounds = availableRounds;

这个代码导致了这个错误,但我稍后会尝试更好地解释这个错误,我需要解释一下这里发生了什么。 本质上应用程序中保存的当前Match应该只更新自己的属性League.Rounds,这个属性是一个Rounds的列表,可用于这个Match,结构很简单:

public class Round
{
    public int Id { get; set; }
    public string Name { get; set; }
}

更新运行良好,但Match.League.Rounds = availableRounds; 行也更新了对象集合Matches 中可用的所有属性League.Rounds

我不明白为什么会这样,我没有创建点击对象的引用:

var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);

正在发生的事情的实践示例

在应用过滤器之前

Matches Collection
   Match.Leagues.Rounds[0] contains Id 10 and Name foo

应用过滤器后

Matches Collection
   Match.Leagues.Rounds[0] contains Id 11 and Name foofoo

但不应该修改,只应该修改Match

但是一个新的对象。有人可以解释如何解决这个问题吗?最好的问候。

【问题讨论】:

  • Match 是 Regex 中的一个类。也许这两个 Match 类混淆了?
  • “在这个事件中我创建了一个被点击的匹配的副本”——你为什么这么认为?您创建了对集合中对象的引用。
  • @jdweng 在这种情况下不是,@Evk 我也尝试过:Match mtc = new Match() 并将这个新对象传递给Match 属性,但结果相同
  • 我认为这可能是由于ObservableCollection的行为

标签: c# wpf linq


【解决方案1】:

我没有创建点击对象的引用

是的,你有。这不会创建一个新的Match 对象:

var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);

它获取对Matches 集合中已经存在的Match 对象的引用。

如果你想创建一个新对象,你应该使用new操作符:

var existing = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
Match match = new Match();
//set all properties of the new object...
match.Prop1 = existing.Prop1;

另外请注意,您还需要创建新的Round 对象。您应该考虑实现IClonable 接口。

FirstOrDefault() 方法不会为您克隆对象。

【讨论】:

  • 所以更好的方法是实现一个克隆对象并且是属性的类,对吧?
  • 是的。您可以实现 ICloneable 接口。
  • 你能告诉我一个更好更快的方法吗?
  • 您需要以一种或另一种方式新建 Match 对象本身和所有子对象。没有更好的方法来克隆对象。我给你看了一个例子。
  • 我已经实现了克隆接口,现在一切正常,非常感谢,祝你有美好的一天:)
猜你喜欢
  • 2018-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-28
  • 1970-01-01
  • 2016-08-13
  • 1970-01-01
  • 2013-01-18
相关资源
最近更新 更多