如何将异步事件转发到父类?

时间:2009-10-02 22:59:43

标签: c# events asynchronous delegates backgroundworker

我不确定将事件传递给父类并且需要一些反馈的最佳方法是什么。

下面的示例代码试图说明我想要实现的目标。

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 个答案:

答案 0 :(得分:3)

我认为你可能刚刚实现了这一点......看起来你正在尝试使用异步操作。即使你正在使用同步操作,通常你只是使用回调方法而不是像这样的情况下的事件......

以下是在此处更改使用回调的示例:

//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);
}

答案 1 :(得分:2)

让每辆车调用一个在父列表上调用事件的事件是没有意义的。我会更喜欢这样做:

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

答案 2 :(得分:2)

这似乎是合理的,但我不确定用例是什么以及如何使用它。

你有一个强烈的遏制概念,但我不确定为什么。此外,有点奇怪的是,CarList'有点'似乎拥有各辆车的所有权。

此外,我不知道为什么Car类上的Test()都会返回结果引发事件。看起来你有两条不同的路径来返回相同的数据。而且,乍一看,对于CarList类,Manager类似乎完全是多余的。

你在这里尝试解决的问题是什么?这可能有助于我为它定义一个好的解决方案。