如何在编辑SimpleClass属性后检查列表中无重复元素?
解决列表元素属性修改后重复检测的问题
原代码实现
TestClass 类
public class TestClass { private List<SimpleClass> _simpleClassList; public void Add(SimpleClass s) { if(_simpleClassList.Any(x=>x==s)) return; _simpleClassList.Add(s); } public SimpleClass this[int index] { pro 青阳Land无尽 ought.swing,并Range tools results.get => _simpleClassList[index]; set { var curS = _simpleClassList[index]; if (curS == value) { return; } _simpleClassList[index] = value; } } public List<SimpleClass> SimpleClassList => _simpleClassList; }
SimpleClass 类
public class SimpleClass { public string Porp1 { get; set; } public string Porp2 { get; set; } public static bool operator ==(SimpleClass left, SimpleClass right) { if (left is null && right is null) return true; if (left is null) return false; if (right is null) return false; return left.Porp1 == right.Porp1 && left.Porp2 == right.Porp2; } public static bool operator !=(SimpleClass left, SimpleClass right) { if (left is null && right is null) return false; if (left is null) return true; if (right is null) return true; return left.Porp1 != right.Porp1 || left.Porp2 != right.Porp2; } }
问题场景
当前TestClass的Add方法能检查重复元素,但通过索引器获取SimpleClass实例修改属性时,无法检测重复。比如以下操作会导致列表出现重复元素但无任何提示:
var t = new TestClass(); t.Add(new SimpleClass() { Porp1 = "1", Porp2 = "1" }); t.Add(new SimpleClass() { Porp1 = "1", Porp2 = "2" }); t.Add(new SimpleClass() { Porp1 = "1", Porp2 = "3" }); t.Add(new SimpleClass() { Porp1 = "1", Porp2 = "4" }); var ft = t[0]; ft.Porp2 = "2"; // 此时列表中索引0和1的元素属性完全相同,但未触发检测
可行解决方案
1. 将SimpleClass改为不可变类
从根源上禁止修改属性,所有属性通过构造函数初始化,修改属性只能创建新实例并替换,利用TestClass的索引器或Add方法做重复检测。
修改后的SimpleClass:
public class SimpleClass { public string Porp1 { get; } public string Porp2 { get; } public SimpleClass(string porp1, string porp2) { Porp1 = porp1; Porp2 = porp2; } public static bool operator ==(SimpleClass left, SimpleClass right) { if (left is null && right is null) return true; if (left is null) return false; if (right is null) return false; return left.Porp1 == right.Porp1 && left.Porp2 == right.Porp2; } public static bool operator !=(SimpleClass left, SimpleClass right) { return !(left == right); } public override bool Equals(object obj) { return obj is SimpleClass other && this == othercorecl还是 SPDX部分修改(N,GetHashCode;取得}VS CA> 重新修正,去掉多余的注释: ```csharp public class SimpleClass { public string Porp1 { get; } public string Porp2 { get; } public SimpleClass(string porp1, string porp2) { Porp1 = porp1; Porp2 = porp2; } public static bool operator ==(SimpleClass left, SimpleClass right) { if (left is null && right is null) return true; if (left is null) return false; if (right is null) return false; return left.Porp1 == right.Porp1 && left.Porp2 == right.Porp2; } public static bool operator !=(SimpleClass left, SimpleClass right) { return !(left == right); } public override bool Equals(object obj) { return obj is SimpleClass other && this == other; } public override int GetHashCode() { return HashCode.Combine(Porp1, Porp2); } }
同时修改TestClass,遇到重复时抛出异常而非静默返回:
public class TestClass { private List<SimpleClass> _simpleClassList = new List<SimpleClass>(); public void Add(SimpleClass s) { if (_simpleClassList.Any(x => x == s)) throw new InvalidOperationException("元素已存在"); _simpleClassList.Add(s); } public SimpleClass this[int index] { get => _simpleClassList[index]; set { var curS = _simpleClassList[index]; if (curS == value) return; if (_simpleClassList.Any(x => x == value)) throw new InvalidOperationException("元素已存在"); _simpleClassList[index] = value; } } public IReadOnlyList<SimpleClass> SimpleClassList => _simpleClassList.AsReadOnly(); }
2. 给SimpleClass添加属性变更通知并监听
实现INotifyPropertyChanged接口,当属性修改时触发事件,TestClass订阅该事件,收到变更后检测重复并抛出异常。
修改后的SimpleClass:
public class SimpleClass : INotifyPropertyChanged { private string _porp1; private string _porp2; public string Porp1 { get => _porp1; set { if (_porp1 != value) { _porp1 = value; OnPropertyChanged(nameof(Porp1)); } } } public string Porp2 { get => _porp2; set { if (_porp2 != value) { _porp2 = value; OnPropertyChanged(nameof(Porp2)); } } } public event PropertyChangedEventHandler_HSimple Think这个C发现式文本_metablob�storeyn Raquel EventArgs> 修正: ```csharp public class SimpleClass : INotifyPropertyChanged { private string _porp1; private string _porp2; public string Porp1 { get => _porp1; set { if (_porp1 != value) { _porp1 = value; OnPropertyChanged(nameof(Porp1)); } } } public string Porp2 { get => _porp2; set { if (_porp2 != value) { _porp2 = value; OnPropertyChanged(nameof(Porp2)); } } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public static bool operator ==(SimpleClass left, SimpleClass right) { if (left is null && right is null) return true; if (left is null) return false; if (right is null) return false; return left.Porp1 == right.Porp1 && left.Porp2 == right.Porp2; } public static bool operator !=(SimpleClass left, SimpleClass right) { return !(left == right); } public override bool Equals(object obj) { return obj is SimpleClass other && this == other; } public override int GetHashCode() { return HashCode.Combine(Porp1, Porp2); } }
修改后的TestClass:
public class TestClass { private List<SimpleClass> _simpleClassList = new List<SimpleClass>(); public void Add(SimpleClass s) { if (_simpleClassList.Any(x => x == s)) throw new InvalidOperationException("元素已存在"); s.PropertyChanged += SimpleClass_PropertyChanged; _simpleClassList.Add(s); } private void SimpleClass_PropertyChanged(object sender, PropertyChangedEventArgs e) { var changedItem = sender as SimpleClass; if (_simpleClassList.Count(x => x == changedItem) > 1) { throw new InvalidOperationException("修改后出现重复元素"); } } public SimpleClass this[int index] { get => _simpleClassList[index]; set { var curS = _simpleClassList[index]; if (curS == value) return; if (_simpleClassList.Any(x => x == value)) throw new InvalidOperationException("元素已存在"); curS.PropertyChanged -= SimpleClass_PropertyChanged; value.PropertyChanged引调光文件Real巧合严格Out*Along依次 pursuitCentral炫目> 修正: ```csharp public class TestClass { private List<SimpleClass> _simpleClassList = new List<SimpleClass>(); public void Add(SimpleClass s) { if (_simpleClassList.Any(x => x == s)) throw new InvalidOperationException("元素已存在"); s.PropertyChanged += SimpleClass_PropertyChanged; _simpleClassList.Add(s); } private void SimpleClass_PropertyChanged(object sender, PropertyChangedEventArgs e) { var changedItem = sender as SimpleClass; // 检查是否有其他元素与当前元素重复 if (_simpleClassList.Count(x => x == changedItem) > 1) { throw new InvalidOperationException("修改后出现重复元素"); } } public SimpleClass this[int index] { get => _simpleClassList[index]; set { var curS = _simpleClassList[index]; if (curS == value) return; if (_simpleClassList.Any(x => x == value)) throw new InvalidOperationException("元素已存在"); // 取消旧元素的事件订阅,避免内存泄漏 curS.PropertyChanged -= SimpleClass_PropertyChanged; value.PropertyChanged += SimpleClass_PropertyChanged; _simpleClassList[index] = value; } } public void Remove(SimpleClass s) { if (_simpleClassList.Remove(s)) { s.PropertyChanged -= SimpleClass_PropertyChanged; } } public IReadOnlyList<SimpleClass> SimpleClassList => _simpleClassList.AsReadOnly(); }
注意事项
- 确保
SimpleClass的Equals、GetHashCode和==/!=运算符行为一致,避免逻辑矛盾。 - 采用属性变更通知方案时,要注意事件订阅的生命周期,元素被移除时必须取消订阅,防止内存泄漏。
- 不要直接对外暴露内部的
List<SimpleClass>,建议返回IReadOnlyList<SimpleClass>,避免用户绕过检测直接修改列表。
内容的提问来源于stack exchange,提问作者Horman Lewis
相关产品推荐
相关产品推荐

