订阅泛型类中的Action

时间:2017-11-22 10:30:23

标签: c#

我正在尝试订阅泛型类中的事件。下面是我的扩展List类的代码。 OnEntityDisable中的操作IEntity需要IEntity作为参数。

我收到此错误消息:

  

预期使用void RemoveItem(IEntity)签名的方法

但是,T是我班级中的IEntity,您可以看到:: IList<T> where T : IEntity。我做错了什么?

public interface IEntity
{
    Action<IEntity> OnEntityDisable { get; set; }   
}

public class SelectionList<T> : IList<T> where T : IEntity
{
    private readonly IList<T> _entities;

    public SelectionList()
    {
        _entities = new List<T>(32);
    }

    public void Add(T item)
    {
        if (item == null)
            return;

        item.OnEntityDisable += RemoveItem; // This line throws an error

        _entities.Add(item);
    }

    public void RemoveItem(T item)
    {
        if (Count <= 0 || item == null)
            return false;

        _entities.Remove(item);
    }
}

2 个答案:

答案 0 :(得分:3)

这是一个逆转问题。每个T都是IEntity,但不是每个IEntity都是T。您的活动将保证您的论点是IEntity,但不能保证您是T。由于RemoveItem需要T,因此无效。

使T逆变不是一个选项,因为SelectionList是一个类,并且逆变只适用于接口,也因为你不能从List<T>继承,因为列表的T 1}}不是逆变的。

您有三种方法可以解决它:

更改RemoveItem

您可以更改RemoveItem接受IEntity而不是T

public void RemoveItem(IEntity item)
{
    if (Count <= 0 || item == null)
        return;

    _entities.Remove((T)item);
}

使用lambda表达式作为事件处理程序

由于更改RemoveItem会更改类界面,因此可能不是您想要的。您可以通过保持原样来帮助自己,并在lambda表达式中执行必要的类型转换:

item.OnEntityDisable += item => RemoveItem((T)item);

使IEntity通用

您可以使IEntity接口通用,并在约束中传递type参数:

public interface IEntity<T>
{
    Action<T> OnEntityDisable { get; set; }   
}

然后

public class SelectionList<T> : IList<T> where T : IEntity<T>
{
    //...
}

答案 1 :(得分:2)

当您订阅接口事件时TIEntityIEntity的实施者没有任何限制强制它传递T作为事件论证。它可以传递任何实现IEntity的类。 。

有两种解决方案:

  1. 使IEntity通用以确保事件参数的类型,并使用限制性更强的类型约束:
  2. 代码:

    public interface IEntity<T>
    {
        Action<T> OnEntityDisable { get; set; }
    }
    public class SelectionList<T> : IList<T> where T : IEntity<T>
    { }
    
    1. 使用中间委托并将参数转换为预期类型:
    2. 代码:

      item.OnEntityDisable += e => RemoveItem((T)e);
      

      第一种解决方案更安全,但使用起来可能更麻烦。第二个解决方案依赖于IEntity的实现,即使没有强制它这样做的类型契约也表现良好。最终取决于您选择哪种解决方案。