Избежать передачи поля дочернего класса в конструктор родительского класса

Есть внешние классы Node1 и Node2 (которые я не могу изменить) и для которых необходимо создать классы-обертки NodeWrapper1 и NodeWrapper2 соответственно

В классе NodeWrapper1 есть поле ID, которое необходимо считать и добавить в список использованных ID

Список использованных ID хранится в поле id_generator (класс IDGenerator) класса NodeListService1

В конструкторе класса NodeListService создается список с классами-обертками с помощью делегата "create_node" (передается через параметр конструктора)

В конструкторе класса NodeListService1 необходимо считать ID с каждого объекта-обертки и добавить в список использованных ID

Это делается с помощью второго цикла по свойству ElementsList

Хотел бы избежать второго цикла по тем же объектам

Если передать поле id_generator в делегат "create_node", то это вызывает ошибку CS0027

Возможно ли добавить использованные ID в id_generator без использования второго цикла?

Код:

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);//ошибка CS0027
            }
    )
    {
        //можно сделать так, но это будет вторым циклом по тем же узлам
        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 and 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 ctor
    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);
}

Ответы (1 шт):

Автор решения: Ramil Shavaleev

По совету Grundy сделал метод OnNodeCreate

Получилось избежать доп. циклов

Код

class NodeListService<T> where T : NodeWrapper, new()
{
    private List<T> lst_node = new();

    protected virtual T OnNodeCreate(Node node) => new T();

    internal NodeListService(List<Node> lst_ext_node)
    {
        foreach (Node cur_node in lst_ext_node)
        {
            this.lst_node.Add(this.OnNodeCreate(cur_node));
        }
    }
}

class NodeListService1 : NodeListService<NodeWrapper1>
{
    private IDGenerator id_generator = new();

    protected override NodeWrapper1 OnNodeCreate(Node node)
    {
        NodeWrapper1 cur_node_wrapper = new((Node1)node);
        this.id_generator.AddID(cur_node_wrapper.ID);

        return cur_node_wrapper;
    }

    internal NodeListService1(List<Node> lst_ext_node) : base(lst_ext_node)
    {
    }
}

class NodeListService2 : NodeListService<NodeWrapper2>
{
    internal NodeListService2(List<Node> lst_ext_node) : base(lst_ext_node)
    {
    }
}

#region Node
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
class NodeWrapper
{
    protected readonly Node NodeValue;

    internal NodeWrapper()
    {
        this.NodeValue = new Node();
    }

    internal NodeWrapper(Node cur_node)
    {
        this.NodeValue = cur_node;
    }
}

class NodeWrapper1 : NodeWrapper
{
    internal readonly int ID;

    #region ctor
    public NodeWrapper1()
    {
    }

    internal NodeWrapper1(Node1 cur_node) : base(cur_node)
    {
        this.ID = cur_node.ID;
    }
    #endregion
}

class NodeWrapper2 : NodeWrapper
{
    internal readonly int SomeOtherField;

    public NodeWrapper2()
    {
    }

    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();

    internal int GetNewID()
    {
        while (hs_used_id.Contains(this.counter++)) ;
        return this.counter;
    }

    internal bool AddID(int id) => hs_used_id.Add(id);
}
→ Ссылка