C# 将项目添加到列表中,但不生效
在C#类中,我有一个列表和两个不同的getter:C# 将项目添加到列表中,但不生效,c#,list,getter,C#,List,Getter,在C#类中,我有一个列表和两个不同的getter: private List<A> a; public List<A> EveryA { get { if (a == null) a = new List<A>(); return a; } } public List<A> FilteredA { get {
private List<A> a;
public List<A> EveryA
{
get
{
if (a == null) a = new List<A>();
return a;
}
}
public List<A> FilteredA
{
get
{
return EveryA.FindAll(a => a.IsInFilter);
}
}
私有列表a;
公开名单EveryA
{
收到
{
如果(a==null)a=newlist();
返回a;
}
}
公共列表过滤器
{
收到
{
返回EveryA.FindAll(a=>a.IsInFilter);
}
}
现在我的问题是:语法如何FilteredA.Add(this)代码>?
它编译并运行,但不能将任何项目添加到任何列表中。
更好的编译器应该通知(小)问题吗?否。为什么要通知您?完全可以。
FilteredA
不返回a
,而是返回列表的新实例
FilteredA.Add(这个)
将此
添加到此新实例
请参阅此代码:
var filteredA = FilteredA;
int count1 = filteredA.Count;
filteredA.Add(this);
int count2 = filteredA.Count;
Assert.AreEqual(count1 + 1, count2);
这表明新项目已添加到列表中。但是对于独立于类中的列表的新实例。FindAll返回一个新列表。我想您正在将新项目添加到新列表中,但没有保留对新列表的引用。如果过滤列表来自方法而不是属性,则语义会更清晰。它们不是同一个列表。这不是编译器可以为您检查的内容,因为编译器无法真正读懂您的心思。检查文档中的
结果是一个列表,但它不是同一个列表(怎么可能?您的原始列表没有被过滤!)
您应该能够将项目添加到FilteredA
返回的列表中,除非它们不会显示在a
中
我建议您改用LINQsWhere
,返回一个IEnumerable
。这样,很明显,FilteredA
的结果不应更改,只应迭代:
public IEnumerable<A> FilteredA
{
get { return EveryA.Where(a => a.IsInFilter); }
}
public IEnumerable过滤器数据
{
获取{return EveryA.Where(a=>a.IsInFilter);}
}
公共列表过滤器数据
返回FindAll
方法的一些输出,作为列表
。这将不是与EveryA相同的对象,因此当它超出范围时,您添加的内容将丢失。这不是真正的编译器问题-因为代码是有效的,所以可以正常编译。问题更多的是在代码质量级别上。要捕获类似的内容,您可以使用类似的工具来分析代码
这两种方法都可以看作是查询方法。不应将结果公开为列表,而应公开为IEnumerable或[]。如果要将项目添加到列表中,请使用add方法
private List<A> items = new List<A>();
public IEnumerable<A> EveryA
{
get { return items; }
}
public IEnumerable<A> FilteredA
{
get { return items.Where(item => item.IsInFilter); }
}
public void AddItem(A item)
{
items.Add(item);
}
private List items=new List();
公共数字EveryA
{
获取{返回项;}
}
公共IEnumerable FilteredA
{
获取{return items.Where(item=>item.IsInFilter);}
}
公共无效附加项(项目)
{
项目。添加(项目);
}
我同意,FilteredA应该是一个方法/函数,而不是一个属性。为什么一个方法会产生更清晰的语义?并且-当属性返回IEnmerable而不是List时,您认为它是否仍然是一个方法(如果是,为什么)?属性意味着一些相当静态的东西;对于两个单独的调用,它应该总是返回相同的内容(当然,除非有人在两个调用之间写入了属性)。具有getter副作用的属性(与读取属性相关的属性除外,比如日志记录或延迟加载)令人困惑,就像在本例中,代码的作者您感到困惑一样。名为GetFilteredA()的方法看起来更像是能够通过每次调用创建新对象。是的,IEnumerable返回方法也应该是一种方法。详细说明一下:我在Google上搜索了方法和属性,第一个搜索结果是“一般来说,属性存储对象的数据,方法是可以要求对象执行的操作”。因此属性获取者专注于检索数据(基础列表),而对该成员的要求是执行一个操作(过滤列表)并返回结果。+1表示linq建议,如果可以的话,+1表示“编译器无法真正读懂您的想法”IEnumerable的建议是非常有用和优雅的,我必须记住这一点。但是,使用Linq的建议对我来说没有太大意义;我看不出我的示例代码中的谓词与“Linq”有什么区别,我只是指System.Linq
中提供的扩展方法,即Where
。与您的示例中的谓词没有区别,事实上,我重用了您的谓词。区别只是Linq版本使用了延迟求值。您仍然可以使用您的版本,只需更改返回类型。我只是从未想过当然……这是一个很好的解决方案。不过我还是有点喜欢公开名单EveryA,可能也是口味的问题吧?@phoog,我糟糕的、固定的答案。