Как переслать асинхронные события в родительские классы? - PullRequest
4 голосов
/ 03 октября 2009

Я не уверен относительно того, что является лучшим подходом для передачи событий по линии родительским классам и нуждается в некоторой обратной связи.

В приведенном ниже примере кода показано, чего я хочу достичь.

namespace test {
public delegate void TestCompletedEventHandler(object sender, 
    TestCompletedEventArgs e);

    public class Manager {
        CarList m_carlist = null;

        public CarList Cars {
            get { return m_carlist; }
            set { m_carlist = value; }
        }

        public Manager() {
            Cars = new CarList(this);
        }

        public void Report(bool successfull) {
            //...
        }
    }

    public class CarList : List<Car> {
        protected internal event TestCompletedEventHandler 
            Car_TestCompleted = null;

        protected readonly Manager m_manager = null;

        public Manager Manager {
            get { return m_manager; }
        }

        public CarList(Manager manager) {
            m_manager = manager;
        }

        public void Test() {
            foreach(Car car in this) {
                bool ret = car.Test();
                manager.Report(ret);
            }
        }

        public void Add(Car car) {
            //Is this a good approach?
            car.TestCompleted += 
                new TestCompletedEventHandler(Car_TestCompleted_Method);
            base.Add(car);
        }

        private void Car_TestCompleted_Method(object sender, 
            TestCompletedEventArgs e) 
        {
            if(Car_TestCompleted != null) Car_TestCompleted(sender, e);
        }
    }

    public class Car {
        protected internal event TestCompletedEventHandler 
            TestCompleted = null;

        public bool Test() {
            //...

            if(TestCompleted != null) TestCompleted(this, 
                new TestCompletedEventArgs())
        }
    }

    public class TestCompletedEventArgs : EventArgs {
        //...
    }
}

using test;
Manager manager = new Manager();
manager.Cars.Car_TestCompleted += 
    new TestCompletedEventHandler (Car_TestCompleted_Method);
manager.Cars.Test();

Еще один более конкретный пример:

//Contains DataItems and interfaces for working with them
class DataList
{
    public List<DataItem> m_dataitems { get; set; }
    public TestManager m_testmanager { get; set; }
    // ...
}

class DataItem
{
    // ...
}

//A manager class for running tests on a DataList
class TestManager 
{
    public List<TestSource> m_sources { get; set; }
    public WorkerManager m_workermanager { get; set; }
    // ...
}

//A common interface for Tests
abstract class TestSource
{
    public event EventHandler<EventArgs<object>> Completed = null;
    protected TestManager m_owner { get; set; }

    public abstract void RunAsync();
    // ...
}

//A test
class Test1 : TestSource
{
    public virtual void RunAsync()
    {
        //Add commands
        //Run workers
        //Report progress to DataList and other listeners (like UI)

        //Events seem like a bad approach since they need to be forwarded through many levels of abstraction
        if(Completed != null) Completed(this, new EventArgs<object>(null));
    }
    // ...
}

//Manages a number of workers and a queue of commands
class WorkerManager
{
    public List<MyWorker> m_workers { get; set; }
    public Queue<Command> m_commands { get; set; }
}

//Wrapper for BackgroundWorker
class MyWorker
{
    // ...
}

//Async command
interface Command
{
    // ...
}

Ответы [ 3 ]

3 голосов
/ 03 октября 2009

Я думаю, вы, возможно, чуть-чуть реализовали это ... Похоже, вы пытаетесь использовать асинхронные операции. Даже если вы используете операции синхронизации, обычно в таких случаях вы просто используете методы обратного вызова вместо событий ...

Вот пример того, что нужно изменить, чтобы использовать обратные вызовы здесь:

//new delegate
public delegate void CarReportCallback(Car theCar, bool result);

//in the Manager class, make report conform to delegate's signature
public void Report(Car theCar, bool result)
{
    //do something, you know which car and what the result is. 
}

//in the CarList class pass a reference to the report method in
public void Test() 
{
    foreach(Car car in this)
    {
        car.Test(manager.Report);
    }
}

//in the Car class use the delegate passed to invoke the reporting 
public void Test(CarReportCallback callback)
{
    //... do stuff
    callback(this, isTestCompleted);
}
2 голосов
/ 03 октября 2009

Это кажется разумным, но я не совсем уверен, каков вариант использования и как это будет использоваться.

У вас есть сильная концепция сдерживания, но я не совсем уверен, почему. Кроме того, довольно странно, что CarList, похоже, владеет отдельными автомобилями.

Кроме того, я не знаю, почему Test () в классе Car будет возвращать результат и , вызывая событие. Кажется, у вас есть два разных пути для возврата одних и тех же данных. И класс Manager, на первый взгляд, совершенно избыточен с классом CarList.

Какую проблему вы на самом деле пытаетесь решить здесь? Это может помочь мне найти правильное решение.

2 голосов
/ 03 октября 2009

Не имеет смысла, чтобы каждая машина вызывала событие, которое вызывает событие в родительском списке. Я бы сделал это больше так:

namespace test {
    public delegate void TestCompletedEventHandler(object sender, 
    TestCompletedEventArgs e);

    public class Manager {
        CarList m_carlist = null;

        public CarList Cars {
            get { return m_carlist; }
            set { m_carlist = value; }
        }

        public Manager() {
            Cars = new CarList(this);
        }

        public void Report(bool successful) {
            //...
        }
    }

    public class CarList : List<Car> {
        protected readonly Manager m_manager = null;
        protected List<Action<object, TestCompletedEventArgs>> delegatesList = new List<Action<object, TestCompletedEventArgs>>();

        public Manager Manager {
            get { return m_manager; }
        }

        public CarList(Manager manager) {
            m_manager = manager;
        }

        public void Test() {
            foreach(Car car in this) {
                bool ret = car.Test();
                manager.Report(ret);
            }
        }
        public void Add(TestCompletedEventHandler e) {
            foreach (Car car in this) {
                car.OnTestCompleted += e;
            }
            delegatesList.Add(e);
        }
        public void Add(Car car) {
        foreach(Action a in delegatesList)
        {
            car.OnTestCompleted += a;
        }
            base.Add(car);
        }
    }

    public class Car {
        protected internal event TestCompletedEventHandler OnTestCompleted = null;

        public bool Test() {
            //...
            if (OnTestCompleted != null) OnTestCompleted(this, new TestCompletedEventArgs());
        }
    }

    public class TestCompletedEventArgs : EventArgs {
        //...
    }
}

using test;
Manager manager = new Manager();
Manager.Cars.Add(new Car());
manager.Cars.Add(new Car());
manager.Cars.Add(new Car());
manager.Cars.Add((sender, args) => 
{
    //do whatever...
})
manager.Cars.Test();
manager.Cars.Add(new Car());
...