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

发布于 2024-08-06 01:37:14 字数 3439 浏览 7 评论 0原文

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

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

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

I'm unsure as to what is the best approach for passing events down the line to parent classes and in need of some feedback.

The example code below tries to illustrate what I want to achieve.

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

Another more specific example:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

如此安好 2024-08-13 01:37:14

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

以下是要更改为使用回调的示例:

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

I think you may have just over implemented this a bit... It looks like you are trying to use async operations. Even if you are using sync operations though, typically you'd just use callback methods instead of events in a case like this...

Here is an example of things to change to use callbacks here:

//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);
}
折戟 2024-08-13 01:37:14

这看起来很合理,但我不太确定用例是什么以及如何使用它。

你有一个强烈的遏制概念,但我不太清楚为什么。另外,CarList“某种程度上”似乎拥有单辆汽车的所有权,这有点奇怪。

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

您实际上想解决的问题是什么?这可能会帮助我定义一个好的解决方案。

It seems reasonable, but I'm not really sure what the use case is and how this would be used.

You've got a strong concept of containment going on, but I'm not really sure why. Also, it's kind of weird that the CarList 'sort of' seems to have ownership of the individual cars.

Additionally, I don't know why Test() on the Car class would both return a result and raise an event. It seems like you're having two different paths to return the same data. And the Manager class seems completely redundant with the CarList class at first glance.

What is the problem you're actually trying to solve here? That might help me with defining a good solution to it.

慢慢从新开始 2024-08-13 01:37:14

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

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

It wouldn't make sense to just have each car call an event which calls an event on the parent list. I would do it more like this:

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());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文