Звиняйте, если чушь напишу, может не сообразил. Есть не важная задача, речь просто о некрасивости при повторении кода, которую мне не удалось устранить в 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();
}
}
}
}