将抽象类的集合作为函数的参数传递

本文关键字:函数 参数传递 集合 抽象类 | 更新日期: 2023-09-27 18:05:23

我想在函数中传递ICollection<AbstractClass>作为参数。但是当我用具体类型的集合调用它时Visual Studio会显示错误

方法有一些无效参数

我的功能是:

    private void GenerateId(ICollection<BaseEntity> entities)
    {
        foreach (BaseEntity e in entities)
        {
           e.Id = _baseDao.GetNextId();
        }
    }

我的电话是:

GenerateId(entity.TitleAdmRegions);

Type of AdmRegions:

public virtual ICollection<TitleAdmRegion> TitleAdmRegions { get; set; }

和AdmRegion是:

public partial class TitleAdmRegion : BaseEntity
{
  //...
}

将抽象类的集合作为函数的参数传递

您必须进行显式强制转换—实际上,不能保证T的集合(其中T继承自U)也是U的集合。当然,很有可能是,但是……

这种关系被称为协方差——在泛型"调用"中使用更具体的类型而不是其祖先的能力。MSDN有一篇关于c#主题的好文章- http://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx

类型安全的方法实际上非常简单,使用泛型:
private void GenerateId<T>(ICollection<T> entities)
  where T: BaseEntity
{
    foreach (var e in entities)
    {
       e.Id = _baseDao.GetNextId();
    }
}

同样,ICollection<T>不是协变的,而IEnumerable<T>是协变的。因此,另一种简单的方法是使用IEnumerable<BaseEntity>作为参数:

private void GenerateId<T>(IEnumerable<T> entities) { ... }

接口ICollection<T>T中不协变。这不可能是因为该类型包含void Add(T item)之类的方法。我们有

一个TitleAdmRegion是一个BaseEntity

但没有协方差,这是否不是意味着

ICollection<TitleAdmRegion>是一个ICollection<BaseEntity>

就像你想的那样。解决方案是切换到在类型参数中协变的接口。您可以使用IEnumerable<out T>IReadOnlyCollection<out T>。协方差表示IEnumerable<TitleAdmRegion>IEnumerable<BaseEntity>, IReadOnlyCollection<TitleAdmRegion>IReadOnlyCollection<BaseEntity>。因此将签名更改为:
private void GenerateId(IEnumerable<BaseEntity> entities) // or IReadOnlyCollection<BaseEntity>, or IReadOnlyList<BaseEntity>, etc.
{
    foreach (BaseEntity e in entities)
    {
       e.Id = _baseDao.GetNextId();
    }
}

一切都会好起来的。

泛型中的协方差(和逆变性)是。net 4.0(2010)的新特性。接口IReadOnlyCollection<out T>在。net 4.5(2012)中是新的。请注意,允许读写的集合(例如List<T>类和T[]数组类型)确实实现了IReadOnlyCollection<out T>