【问题标题】:How to forward asynchronous events to parent classes?如何将异步事件转发给父类?
【发布时间】:2009-10-02 22:59:43
【问题描述】:

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

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

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
{
    // ...
}

【问题讨论】:

  • 您不想将它们向上传递给父母吗? ;)

标签: c# events asynchronous delegates backgroundworker


【解决方案1】:

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

这里是一个改变使用回调的例子:

//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】:

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

    你对正在进行的收容有一个强烈的概念,但我不确定为什么。此外,CarList 似乎拥有每辆汽车的所有权,这有点奇怪。

    另外,我不知道为什么 Car 类上的 Test() 会同时返回结果引发事件。似乎您有两条不同的路径来返回相同的数据。乍一看,Manager 类似乎与 CarList 类完全多余。

    您在这里真正要解决的问题是什么?这可能有助于我定义一个好的解决方案。

    【讨论】:

    • 我用更具体的例子更新了原始问题。大多数“繁重”代码在异步工作线程中运行,它们需要在完成运行/更改状态/进度等时报告聚合链。
    【解决方案3】:

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

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

    【讨论】:

    • 如果在使用“manager.Cars.Add((sender, args)”设置 EventHandler 后添加更多汽车怎么办?
    • 嗯....好问题。我可能会想出更好的东西,等等。在这里,已编辑。
    • 这当然不会处理删除事件,因为你需要添加一个类似于 Add one 的 Remove 方法,只是它做相反的事情。
    猜你喜欢
    • 2016-01-20
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    • 2019-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    相关资源
    最近更新 更多