#c# #.net
#c# #.net
Вопрос:
Я новичок в C #. У меня есть метод в базовом классе, который запускает другой метод, который может быть переопределен
public abstract class BaseClass
{
protected SomeResults processAllItems()
{
//code process All Items one by one
for(Item item : allItems)
{ processItem(item); }
}
protected abstract void processItem(Item item);
}
class MyInheritingClass : BaseClass
{
protected override void processItem(Item item)
{
// do my task
}
}
что я хочу сделать, так это запустить метод ProcessItem() параллельно. Однако я не могу переопределить метод запуска processAllItems()Я могу сделать что-то вроде
class MyInheritingClass : BaseClass
{
protected override void processItem(Item item)
{
Task.run(() => runTask(item) )
}
protected override void runTask(Item item )
{
// do my task here
}
}
Но у меня есть следующие проблемы
- ProcessItem просто поставит все элементы в очередь, а processAllItems предположит, что все элементы обрабатываются, пока они все еще выполняются асинхронно
- Если я использую task.подождите, он вернется к той же проблеме, когда элементы будут обрабатываться один за другим, а не параллельно. Может кто-нибудь помочь мне с тем, как я могу запустить ProcessItem параллельно и гарантировать, что processAllItems завершится только тогда, когда все элементы будут обработаны.
- могу ли я переопределить processAllItems()?
Комментарии:
1. Можете ли вы изменить реализацию
processAllItems()
в своем базовом классе?2. определить переопределение? вы имеете в виду, что вы не можете изменить реализацию?
3. Нет. Это часто используемый класс, смогу ли я переопределить защищенные SomeResults processAllItems()??
4. под переопределением я подразумеваю изменение реализации processAllItems, где я мог бы изменить способ запуска ProcessItem
5. Почему бы не сделать
processAllItems()
virtual, чтобы вы могли его переопределить?:protected virtual SomeResults processAllItems()
Ответ №1:
Самый простой способ — сделать processAllItems()
виртуальный. В этом случае вы можете переопределить его и изменить его поведение в вашем подклассе.
Если в вашем случае это невозможно (например, потому BaseClass
, что является частью внешней библиотеки), вы можете использовать new
ключевое слово в вашем подклассе:
public class MyInheritingClass : BaseClass
{
protected new SomeResults processAllItems()
{
Parallel.ForEach(allItems, processItems);
}
}
Но это имеет серьезный недостаток:
BaseClass test = new MyInheritingClass();
test.processAllItems(); // will call the version of the base class in process in sequence
MyInheritingClass test2 = new MyInheritingClass();
test2.processAllItems(); // will call the version of the subclass in process in parallel
Вы должны проверить, можете ли вы применить new
ключевое слово в своей базе кода.
Совершенно другое решение, которое может вам помочь: знаете ли вы, какой последний элемент allItems
? Тогда вы можете сделать что-то вроде этого:
class MyInheritingClass : BaseClass
{
private List<Task> tasks = new List<Task>();
protected override void processItem(Item item)
{
tasks.Add(Task.run(() => runTask(item) ));
if(item == lastItem)
{
Task.WaitAll(tasks.ToArray());
tasks.Clear();
}
}
protected override void runTask(Item item )
{
// do my task here
}
}
Комментарии:
1. На самом деле, это не будет работать так, как написано выше: каждый экземпляр MyInheritingClass будет иметь свой собственный список задач, добавляя в него только свою собственную задачу ProcessItem. Только ‘lastitem будет ждать завершения… Вы можете изменить это поведение, сделав «задачи» статическими и используя отложенное создание экземпляра в конструкторе…