You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何传递委托引用给其他类,实现单个订阅者监听多个发布者?

嘿,这个场景我太熟悉了——重复给每个商店写监听逻辑确实又繁琐又容易出错!结合你的需求,我整理了几个更优雅的方案,你可以根据现有代码结构来选择:

更优雅地跨多个商店类监听对象添加事件

先再明确下你的核心需求:

有VegetableStore和MeatStore两个类,分别处理继承自同一基类的VegType和MeatType对象;希望在独立类中监听这两个类的新对象添加事件,避免繁琐的重复实现。

方案1:抽象泛型基商店类,统一事件定义

如果还能修改商店类的结构,这是最推荐的方案——通过泛型基类把事件逻辑统一,让监听类只需要写一次通用处理逻辑,就能兼容所有子类商店。

示例代码:

// 所有产品的共同基类
public abstract class ProductType { }
public class VegType : ProductType { }
public class MeatType : ProductType { }

// 泛型基商店类,统一定义添加事件
public abstract class StoreBase<T> where T : ProductType
{
    // 事件用泛型参数,同时保证产品类型是ProductType的子类
    public event EventHandler<ProductAddedEventArgs<T>> ProductAdded;

    // 封装事件触发逻辑,子类直接调用即可
    protected void OnProductAdded(T product)
    {
        ProductAdded?.Invoke(this, new ProductAddedEventArgs<T>(product));
    }
}

// 通用事件参数类
public class ProductAddedEventArgs<T> : EventArgs where T : ProductType
{
    public T Product { get; }
    public ProductAddedEventArgs(T product) => Product = product;
}

// 具体蔬菜商店,继承基类
public class VegetableStore : StoreBase<VegType>
{
    public void AddVeg(VegType veg)
    {
        // 这里写你的蔬菜添加业务逻辑
        OnProductAdded(veg);
    }
}

// 具体肉类商店,同样继承基类
public class MeatStore : StoreBase<MeatType>
{
    public void AddMeat(MeatType meat)
    {
        // 肉类添加业务逻辑
        OnProductAdded(meat);
    }
}

// 独立监听类,只需要一套逻辑
public class ProductMonitor
{
    // 通用订阅方法,适配所有StoreBase子类
    public void SubscribeToStore<T>(StoreBase<T> store) where T : ProductType
    {
        store.ProductAdded += HandleProductAdded;
    }

    // 统一的事件处理方法,可通过is/as判断具体产品类型做差异化处理
    private void HandleProductAdded(object sender, ProductAddedEventArgs<ProductType> e)
    {
        Console.WriteLine($"新增产品:{e.Product.GetType().Name}");
        
        if (e.Product is VegType veg)
        {
            // 针对蔬菜的特殊处理逻辑
        }
        else if (e.Product is MeatType meat)
        {
            // 针对肉类的特殊处理逻辑
        }
    }
}

这个方案的好处是从根源上统一了事件结构,后续新增其他类型的商店(比如SeafoodStore),只需要继承StoreBase<T>,监听类完全不需要修改,扩展性拉满。

方案2:利用事件协变性(适配已有代码结构)

如果已经有现成的VegetableStore和MeatStore,不想动它们的结构,那可以利用.NET 4.0+支持的委托协变性,把两个商店的事件绑定到同一个处理方法上。

示例代码:

// 原有类结构(假设无法修改)
public abstract class ProductType { }
public class VegType : ProductType { }
public class MeatType : ProductType { }

public class VegetableStore
{
    public event EventHandler<VegAddedEventArgs> VegAdded;

    public void AddVeg(VegType veg)
    {
        VegAdded?.Invoke(this, new VegAddedEventArgs(veg));
    }
}

public class VegAddedEventArgs : EventArgs
{
    public VegType Veg { get; }
    public VegAddedEventArgs(VegType veg) => Veg = veg;
}

public class MeatStore
{
    public event EventHandler<MeatAddedEventArgs> MeatAdded;

    public void AddMeat(MeatType meat)
    {
        MeatAdded?.Invoke(this, new MeatAddedEventArgs(meat));
    }
}

public class MeatAddedEventArgs : EventArgs
{
    public MeatType Meat { get; }
    public MeatAddedEventArgs(MeatType meat) => Meat = meat;
}

// 独立监听类
public class ProductMonitor
{
    public void Subscribe(VegetableStore vegStore, MeatStore meatStore)
    {
        // 利用协变性,把不同事件绑定到同一个处理方法
        vegStore.VegAdded += HandleProductAdded;
        meatStore.MeatAdded += HandleProductAdded;
    }

    // 统一处理方法,通过判断事件参数类型获取具体产品
    private void HandleProductAdded(object sender, EventArgs e)
    {
        ProductType product = null;
        
        if (e is VegAddedEventArgs vegArgs)
            product = vegArgs.Veg;
        else if (e is MeatAddedEventArgs meatArgs)
            product = meatArgs.Meat;

        if (product != null)
        {
            Console.WriteLine($"新增产品:{product.GetType().Name}");
            // 在这里添加具体的处理逻辑
        }
    }
}

这个方案不需要修改原有商店类,只需要在监听类中做一次参数类型判断,就能实现统一处理,非常适合已有代码的改造场景。

方案3:中介者模式(复杂系统的解耦利器)

如果你的系统后续会扩展更多商店类型或者监听者,那中介者模式是更好的选择——它能完全解耦商店和监听类,让两者都依赖中介者,避免直接引用。

示例代码:

// 中介者接口,定义通知行为
public interface IProductMediator
{
    void NotifyProductAdded(ProductType product);
    void RegisterListener(IProductListener listener);
}

// 具体中介者,负责转发事件通知
public class ProductMediator : IProductMediator
{
    private readonly List<IProductListener> _listeners = new();

    public void RegisterListener(IProductListener listener)
    {
        _listeners.Add(listener);
    }

    public void NotifyProductAdded(ProductType product)
    {
        foreach (var listener in _listeners)
        {
            listener.OnProductAdded(product);
        }
    }
}

// 监听者接口,定义处理方法
public interface IProductListener
{
    void OnProductAdded(ProductType product);
}

// 商店类依赖中介者,不再直接定义事件
public class VegetableStore
{
    private readonly IProductMediator _mediator;

    public VegetableStore(IProductMediator mediator) => _mediator = mediator;

    public void AddVeg(VegType veg)
    {
        // 业务逻辑...
        _mediator.NotifyProductAdded(veg);
    }
}

public class MeatStore
{
    private readonly IProductMediator _mediator;

    public MeatStore(IProductMediator mediator) => _mediator = mediator;

    public void AddMeat(MeatType meat)
    {
        // 业务逻辑...
        _mediator.NotifyProductAdded(meat);
    }
}

// 具体监听类,实现监听者接口
public class ProductMonitor : IProductListener
{
    public void OnProductAdded(ProductType product)
    {
        Console.WriteLine($"新增产品:{product.GetType().Name}");
        // 具体处理逻辑...
    }
}

这个方案的优势是完全符合开闭原则,后续新增商店类型或者监听者,只需要实现对应的接口,不需要修改现有代码,非常适合复杂的大型系统。


内容的提问来源于stack exchange,提问作者Cerzi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:17:36