Множественные синглтоны на C#: Nemerle может помочь?
От: FDSC Россия consp11.github.io блог
Дата: 20.05.10 00:25
Оценка:
Звиняйте, если чушь напишу, может не сообразил. Есть не важная задача, речь просто о некрасивости при повторении кода, которую мне не удалось устранить в C#. В макросах Nemerle не силён, но, насколько мне помниться, если что-то может решить проблему, то они. Ну, или я туплю что-то.
Пишу проект на C#, есть примерно такой код:

базовый класс
// Просто базовый класс. Он практически ничего не делает. Объявляет поле статуса операции и то, что операция выполняется через пул потоков
public abstract class getApiData
        {
            protected abstract void calc(Object threadContext);

            protected int      status = 0;
            public    int      Status
            {
                get {return status;}
            }

            public readonly ManualResetEvent endedEvent =  new ManualResetEvent(false);

            public readonly MySqlQuery query;
            public getApiData(MySqlQuery query)
            {
                this.query = query;
            }

            public bool pExec()
            {
                endedEvent.Reset();
                return ThreadPool.QueueUserWorkItem(calc);
            }
    }


один из типичных потомков
public class getEquipmentChilds: getApiData
        {
        // ничего важного: здесь происходит регистрация обработчика события изменения данных
        private getEquipmentChilds(MySqlQuery query): base(query)
            {
                AEUpdateEvent = ComponentDataUpdaterManager.singleManager.insertIntoStartUpdateTarget(ComponentDataUpdaterManager.updateTargets.allEquipment,   updateWordHandler, this, 0);
                updateWordHandler();
            }
            ComponentDataUpdaterManager.handlerUpdateEvent AEUpdateEvent;

            public void updateWordHandler()
            {
                pExec();
            }

                        // Вот этот метод дублируется в каждом классе, его назначение - вызвать статический конструктор, как только сам метод вызван и ничего не делать, если конструктор уже есть
                        // Его нельзя перенести в предок, т.к. тогда инициализироваться при вызове будет именно предок, даже если вызывать явно по имени класса-потомка
                        // Понятно, что его можно заменить макросом, который вставит соотв. код. Но его нужно будет вставлять в каждый класс, а не в потомок.
                        // Возможно ли решение, где каждый класс-потомок сразу будет получать этот код без явного указания макроса или чего бы то ещё, кроме самого факта наследования?
            public static void init()
            {
            }

                        // Вот это поле есть в каждом потомке и называется оно одинаково, но в каждом потомке оно разного типа (собственно, объявляемого типа, это и есть синглтон)
                        // Можно ли его заменить макросом и что для этого потребуется? Можно ли определить такой макрос только в базовом классе (т.е. чтобы потомок не содежал даже упоминания такого макроса)
                        // Можно ли сообщить компилятору, что в каждом классе, наследованном от getApiData,
                        // есть и обязано быть такое поле, что оно является наследником getApiData и его тип совпадает с определяемым типом (в данном случае с типом getEquipmentChilds )?
            public readonly static getEquipmentChilds ewObject  = new getEquipmentChilds(MySqlQuery.query);

                        // Это свойство есть в каждом методе и просто упрощает работу с событием ожидания endedEvent (убирает лишнюю точку)
                        // Его нельзя перенести в предок, т.к. ewObject тоже тогда нужно перенести в предок,
                        // но при этом он потеряет информацию о конкретном типе объекта (станет getApiData),
                        // кроме этого, это свойство представляет статическое поле, которое должно быть одно и только одно на каждый класс.
            public static ManualResetEvent ended
            {
                get
                {
                    return ewObject.endedEvent;
                }
            }

                        // далее ничего интересного и непереносимого даже в C# в потомок нет, кроме блока finally в конце
            public class Child
            {
                public readonly int      id, parent, child;

                public Child(MySqlDataReader reader)
                {
                    id        = reader.GetInt32("ID");
                    parent    = reader.GetInt32("parentCatID");
                    child    = reader.GetInt32("childCatID");
                }
            }

            public SortedList<int, Child> words = null;

            public string errMsg = "";
            public int errCode   = 0;
            protected override void calc(Object threadContext)
            {
                MySqlDataReader reader = null;
                try
                {
                    status = 0;
                    reader = query.executeReader("select ID, parentCatID, childCatID from equipmentChildsView");

                    words = new SortedList<int, Child>(count);
                    while (reader.Read())
                    {
                        words.Add(reader.GetInt32("ID"), new Child(reader));
                    }
                }
                catch (MySqlException e)
                {
                    status  = -1;
                    errMsg  = e.Message;
                    errCode = e.Number;
                }
                catch (Exception e)
                {
                    status = -1;
                    errMsg = e.Message;
                }
                finally
                {
                    try
                    {
                        if (reader != null)
                            reader.Close();
                    }
                    finally
                    {       endedEvent - это свойство, которое, как описано выше, не может быть само по себе перенесено в базвый класс
                        endedEvent.Set();
                    }
                }
            }
        }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.