c# - 迭代器变量在它来自的 IEnumerable 中不存在?
问题描述
我有一个看起来像的方法
private Component[] AssociateComponentsWithParametersAndValues(
IEnumerable<Component> components,
IEnumerable<ComponentParameter> parameters,
IEnumerable<ComponentParameterValue> values
)
{
var componentsDictionary = new Dictionary<string, Component>();
var parametersDictionary = new Dictionary<string, ComponentParameter>();
var valuesDictionary = new Dictionary<string, ComponentParameterValue>();
foreach (Component c in components)
{
bool componentMatch = components.Any(co => co == c);
bool identifierMatch = components.Any(co => co.Identifier == c.Identifier);
if (!componentsDictionary.ContainsKey(c.Identifier))
componentsDictionary.Add(c.Identifier, c);
}
// Do a bunch of stuff to mutate the components
return components.ToArray();
}
你会这样想,componentMatch
而且identifierMatch
每次都是真的,对吧?相反,componentMatch
它始终是错误的,并且identifierMatch
始终是正确的。此外,标识符(几乎,偶尔会有一些不良数据)始终是唯一的,因此它不能找到具有相同标识符的另一个组件。
所以,Component 类一定有什么奇怪的地方。好吧,这就是它的样子
public class Component : ConfigurationObject
{
public string Parent { get; set; }
public string Type { get; set; }
public string Module { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string TypeName { get; set; }
public bool? Enabled { get; set; }
public string DBIdentifier { get; set; }
public Dictionary<string, ComponentParameterAndValues> ParametersAndValues { get; set; }
public override string Identifier => DBIdentifier;
}
这是它实现的类
public abstract class ConfigurationObject
{
public abstract string Identifier { get; }
}
为什么会这样?
解决方案
我能看到这个中断的唯一方法是,如果IEnumerable<Component> components
是一个惰性求值的可枚举,每次都返回新的迭代器对象。这有效:
var list = new List<Component>
{
new Component { Identifier = "Foo" },
new Component { Identifier = "Bar" },
new Component { Identifier = "Baz" },
};
foreach (Component c in list)
{
bool componentMatch = list.Any(co => co == c);
Console.WriteLine($"Component {c.Identifier} match: {componentMatch}");
}
因为==
检查引用相等性(除非Component
覆盖它,但它看起来不像它)。但是,如果它不是列表,而是每次迭代的新结果:
IEnumerable<Component> list = GetList();
foreach (Component c in list)
{
bool componentMatch = list.Any(co => co == c);
Console.WriteLine($"Component {c.Identifier} match: {componentMatch}");
}
private static IEnumerable<Component> GetList()
{
yield return new Component { Identifier = "Foo" };
yield return new Component { Identifier = "Bar" };
yield return new Component { Identifier = "Baz" };
}
然后它打印,false
因为每个都得到一个新对象的新集合,所以它们的引用不匹配。foreach()
Any()
解决方案是枚举一次,将组件存储一次,在列表中具体化,然后使用:
var localComponents = components.ToList();
foreach (Component c in localComponents)
{
// ...
}
推荐阅读
- docker - 无法从 Docker 中的扩展 Kafka 集群访问主题
- javascript - 使用 Web 技术显示基于设备旋转的 3D 模型
- java - 使用 JAVA 使用 XPATH 将 xml 值存储为 Map
- node.js - 有没有办法从 AWS S3 “npm install”?
- r - 在每次循环迭代后运行一个循环并执行一个函数:r
- javascript - PHP转AJAX,只出现一个复选框
- html - CSS变换:将子项的左上角旋转到父项的左下角
- jquery - 从文件选择器中选择文件时出现“C:\\fakepath\\file.txt”问题
- java - 如何避免响应错误:429 Too Many Requests
- java - GridBagLayout 未对齐 jlabel 和 jbutton