0

I have this model structure:

[Table("Image")]
public abstract class CBaseImage
{

    public int ID { get; set; }


    [Required]
    public string Extension { get; set; }

    [MaxLength(11)]
    [Required]
    public string OriginalUrl { get; set; }

    [MaxLength(11)]
    [Required]
    public string ThumbUrl { get; set; }

    public int OrderNumber { get; set; }
}




public class CNewBuildingLayoutImage : CBaseImage
{
    public int NewBuildingLayoutID { get; set; }
    public virtual CNewBuildingLayout NewBuildingLayout { get; set; }


    [AImageFormat(527, 584, false)]
    [MaxLength(11)]
    [Required]
    public string WH_527_584_Url { get; set; }


    [AImageFormat(304, 342, false)]
    [MaxLength(11)]
    [Required]
    public string WH_304_342_Url { get; set; }



}

and

[Table("NewBuildingLayout")]

public class CNewBuildingLayout
{

    public int ID { get; set; }
    //.........

    public virtual ICollection<CNewBuildingLayoutImage> Images { get; set; }

}

At some point I need to use CNewBuildingLayout.Images which is ICollection<CNewBuildingLayoutImage> AS ICollection<CBaseImage>, but when I do:

(ICollection<CBaseImage>)someLayout.Images

I get:

Unable to cast object of type 'System.Collections.Generic.HashSet'1[Models.CNewBuildingLayoutImage]' to type 'System.Collections.Generic.HashSet'1[Models.CBaseImage]'.

I tried

  (ICollection<CBaseImage>)someLayout.Images.Cast<CBaseImage>()

with same result.

How do I cast ICollection<Subclass> to ICollection<BaseClass>?

Roman
  • 1,946
  • 3
  • 20
  • 28
  • 1
    This cannot be done. If you get `ICollection`, you would be able to call `Add` and pass some `CBaseImage` derived class that is not `CNewBuildingLayoutImage`. – Yacoub Massad Mar 04 '16 at 11:20
  • I suppose you're right. If you write this as an answer I'll accept that – Roman Mar 04 '16 at 11:48
  • @Roman - You're wrong about your additional information. The type `ICollection` is an in-memory collection and nothing to do with the records being stored in a database. The duplicate is correct. – Enigmativity Mar 04 '16 at 12:33
  • @Enigmativity in chapter "Lazy Loading" here (https://msdn.microsoft.com/en-us/data/jj574232.aspx) is explained how property `public virtual ICollection Posts { get; set; }` loads related Posts only when iterating thru it, unless I'm losing something – Roman Mar 04 '16 at 12:43
  • @Roman - Yes you are. The type is still an in-memory collection even if it lazily loads the data and all the normal casting rules apply. – Enigmativity Mar 04 '16 at 13:02
  • It is a type safety violation, if this could work then you could add *another* class object that derives from CBaseImage. Violating the guarantee that the HashSet only contains CNewBuildingLayoutImage objects. You either have to create a hashet of CBaseImages or use a covariant interface type like IEnumerable<>. IEnumerable is safe because it cannot modify the collection. – Hans Passant Mar 04 '16 at 13:03
  • @Enigmativity thanks, you're right. I checked logs to database during debug and it gets all related data when just accessing> property for the first time, before iterating or whatever, which means when I need to use this property data is already loaded into memory from db. And article says: "first time the Posts navigation property is accessed". Type is in-memory collection, duplicate mark is valid. – Roman Mar 04 '16 at 13:23
  • @Hans Passant understood. Yes, this makes sense. Thanks for mentioning covariant interface, I'll keep that in mind – Roman Mar 04 '16 at 13:30

0 Answers0