如何解决CS0027错误,在NodeListService1构造中避免二次循环添加ID?
能否在Test1类的构造函数中,将this.lst字段传递给Test类的构造函数(不将lst字段设为static)?
代码示例:
class Test { internal Test(List<int> lst) { lst.Add(1); } } class Test1 : Test { private List<int> lst = new(); internal Test1() : base(this.lst) { } }
代码
class NodeListService<T> where T : NodeWrapper { private List<T> lst_node = new(); internal IList<T> ElementsList { get => this.lst_node.AsReadOnly(); } internal NodeListService(List<Node> lst_ext_node, Func<Node, T> create_node) { // 遍历列表 foreach (Node cur_node in lst_ext_node) { T cur_node_wrapper = create_node(cur_node); this.lst_node.Add(cur_node_wrapper); } } } class NodeListService1 : NodeListService<NodeWrapper1> { private IDGenerator id_generator = new(); internal NodeListService1(List<Node> lst_ext_node) : base ( lst_ext_node, cur_node => { NodeWrapper1 cur_node_wrapper = new((Node1)cur_node); this.id_generator.AddID(cur_node_wrapper.ID);// 不允许这么做 } ) { // 可以这么实现,但会在基类构造函数的循环之后,对节点进行第二次遍历 foreach (NodeWrapper1 cur_node_wrapper in this.ElementsList) { this.id_generator.AddID(cur_node_wrapper.ID); } } } class NodeListService2 : NodeListService<NodeWrapper2> { internal NodeListService2(List<Node> lst_ext_node) : base(lst_ext_node, cur_node => new NodeWrapper2((Node2)cur_node)) { } } #region Node // Node、Node1和Node2是外部实现,无法修改 class Node { } class Node1 : Node { internal int ID; internal Node1(int id) { this.ID = id; } } class Node2 : Node { internal readonly int OtherField; internal Node2(int other_field) { this.OtherField = other_field; } } #endregion #region NodeWrapper // NodeWrapper1和NodeWrapper2是我为Node1和Node2分别创建的包装类 // 它们继承自NodeWrapper,因为两者都需要访问NodeValue字段 class NodeWrapper { protected readonly Node NodeValue; internal NodeWrapper(Node cur_node) { this.NodeValue = cur_node; } } class NodeWrapper1 : NodeWrapper { internal readonly int ID; #region 构造函数 internal NodeWrapper1(Node1 cur_node) : base(cur_node) { this.ID = cur_node.ID; } #endregion } class NodeWrapper2 : NodeWrapper { internal readonly int SomeOtherField; internal NodeWrapper2(Node2 cur_node) : base(cur_node) { this.SomeOtherField = cur_node.OtherField; } } #endregion class IDGenerator { private int counter = 0; private HashSet<int> hs_used_id = new(); // 如果要创建新的Node1(及其对应的NodeWrapper1),需要生成递增的ID internal int GetNewID() { while (hs_used_id.Contains(this.counter++)) ; return this.counter; } internal bool AddID(int id) => hs_used_id.Add(id); }
场景与问题说明
存在外部不可修改的Node、Node1、Node2类,需为其创建对应的NodeWrapper1、NodeWrapper2包装类,以及NodeListService1、NodeListService2类分别管理这些包装类的列表。NodeWrapper1类包含ID字段,需将该字段值读取并添加至NodeListService1类的id_generator字段(IDGenerator类实例)中的已用ID列表。
NodeListService基类在构造函数中通过create_node委托循环创建包装类并加入内部列表。目前在NodeListService1的构造函数中,只能通过二次遍历ElementsList属性获取的包装类节点来添加ID;尝试将NodeListService1的id_generator字段传递给create_node委托时,会触发CS0027错误。
请问是否存在无需二次循环即可将已用ID添加至id_generator的实现方法?
方法一:提前初始化id_generator并通过闭包传递
先在NodeListService1的公开构造函数外初始化id_generator,再通过私有构造函数将其传入闭包,这样就能在创建NodeWrapper1时直接调用AddID,避免二次遍历。
修改后的NodeListService1代码:
class NodeListService1 : NodeListService<NodeWrapper1> { private readonly IDGenerator id_generator; internal NodeListService1(List<Node> lst_ext_node) : this(lst_ext_node, new IDGenerator()) { } // 私有构造函数,接收提前初始化的IDGenerator private NodeListService1(List<Node> lst_ext_node, IDGenerator generator) : base(lst_ext_node, cur_node => { NodeWrapper1 wrapper = new((Node1)cur_node); generator.AddID(wrapper.ID); return wrapper; }) { this.id_generator = generator; } }
方法二:扩展基类构造函数,添加回调委托
如果允许修改基类NodeListService,可以新增一个构造函数,除了create_node外,再添加Action<T>类型的回调,用于在创建包装类后执行额外操作(比如添加ID)。
修改后的基类和NodeListService1:
class NodeListService<T> where T : NodeWrapper { private List<T> lst_node = new(); internal IList<T> ElementsList => lst_node.AsReadOnly(); // 保留原有构造函数 internal NodeListService(List<Node> lst_ext_node, Func<Node, T> create_node) : this(lst_ext_node, create_node, _ => { }) { } // 新增构造函数,支持创建后的回调 internal NodeListService(List<Node> lst_ext_node, Func<Node, T> create_node, Action<T> postCreateAction) { foreach (Node cur_node in lst_ext_node) { T wrapper = create_node(cur_node); lst_node.Add(wrapper); postCreateAction(wrapper); // 执行回调 } } } class NodeListService1 : NodeListService<NodeWrapper1> { private IDGenerator id_generator = new(); internal NodeListService1(List<Node> lst_ext_node) : base(lst_ext_node, cur_node => new NodeWrapper1((Node1)cur_node), wrapper => id_generator.AddID(wrapper.ID)) { } }
内容的提问来源于stack exchange,提问作者Ramil Shavaleev

