将Collection <derived>转换为Collection <base /> </derived>

时间:2012-12-31 15:00:05

标签: c# inheritance

这里有另一个简单的问题,就是在逃避我。

我有2个班级:

namespace Assets
{
   public class BaseAsset
   {
       // Code here
   }
}

并且

namespace Assets
{
   public class Asset : BaseAsset
   {
       // Code here
   }
}

我有一个从数据库返回Asset集合的函数,我希望另一个函数执行该函数并返回一个BaseAsset集合。 我试过这个:

    public static Collection<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
    {
        return (Collection<BaseAsset>)AssetData.getAssets(CategoryId, UserId, CompanyId);
    }

但你可以猜到,它不起作用。 如果我正在使用列表,我可以这样做:

    public static List<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
    {
        return AssetData.getAssets(CategoryId, UserId, CompanyId).Cast<BaseAsset>().ToList();
    }

但我更喜欢使用一个系列,有人能想出一个优雅的解决方案吗?

干杯, r3plica

5 个答案:

答案 0 :(得分:10)

这是一个非常常见的问题。您需要的功能的名称是通用协方差;也就是说,“如果长颈鹿是一种动物,那么长颈鹿列表就是一种动物名单。”

问题是长颈鹿的名单不是一种动物名单。你可以将一只老虎放入动物名单中,但是你不能将老虎放入长颈鹿名单中,因此长颈鹿名单不能用于预计会有动物名单的任何情况。

您应该使用IEnumerable<T>而不是Collection<T>的原因是因为从C#4开始,IEnumerable<T>在T中是协变的,前提是提供的类型参数都是引用类型。也就是说,字符串序列可以用作对象序列,因为它们都是引用类型。但是一系列int不能用作对象序列,因为一个是值类型。

这是安全的原因是因为无法将老虎插入IEnumerable<Giraffe>

答案 1 :(得分:2)

如果您想要.ToList的简易性,只需编写自己的.ToCollection扩展方法即可。实现应该是直截了当的 - 采用IEnumerable<T>,循环遍历它并将所有内容添加到Add的集合中。

答案 2 :(得分:1)

问题是Collection<T>ICollection<T>是不变的(即Collection<BaseAsset>既不是子类型也不是Collection<Asset>的超类型。)

通过返回IEnumerable<BaseAsset>IReadOnlyList<BaseAsset>而不是Collection<BaseAsset>,可以轻松解决问题。

也就是说,你可以写:

public static IEnumerable<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
{
    return AssetData.getAssets(CategoryId, UserId, CompanyId);
}

演员阵容变得不必要了。

通常,您应该更喜欢接口类型(例如IList<T>IReadOnlyList<T>ICollection<T>IEnumerable<T>)而不是具体类型(Collection<T>或{{ 1}})指定返回值和函数参数时。

答案 3 :(得分:0)

为什么不提取界面并使用它,而不是尝试强制转换为基类。

答案 4 :(得分:0)

由于Collection<T>类有一个以IList<T>为参数的构造函数,因此您可以随时执行:

Collection<BaseAsset> = new Collection<BaseAsset>(
                                           assetList.Cast<BaseAsset>().ToList());

当然,如果您需要重用此行为,则可以生成CastToCollection扩展名:

public static Collection<TResult> CastToCollection<TResult>(this IEnumerable source)
{
   return new Collection<TResult>(source.Cast<TResult>().ToList());
}