0

I have a class QuoteAddress which inherits from Address, and a generic collection called AddressCollection which holds these address objects.

When I try to cast a QuoteAddress to Address, everything works fine. But when I try to cast AddressCollection<QuoteAddress> to AddressCollection<Address> I get a compile-time error:

Cannot implicitly cast type AddressCollection<QuoteAddress> to AddressCollection<Address>.

EDIT: I don't believe this question is a duplicate because the suggested duplicate question assumes the collection is ReadOnly. I need to be able to Add/Remove items from my collection.

What can I do to work around this? Since one inherits from the other, I thought this would be a straightforward cast.

public class QuoteAddress : Address
{
   ...
}

I also have an AddressCollection class which holds these addresses.

public class AddressCollection<T> : AddressHack where T : Address, new()
{
   ...
}

I have two client objects that each have a property called Addresses which hold addresses. Client1's Address proprety is of type AddressCollection<QuoteAddress>, while Client2's is of type AddressCollection<Address>.

Client1

public class Client1
{
   ...
   public AddressCollection<QuoteAddress> Addresses { get; set; }
   ...
}

Client2

public class Client2
{
   ...
   public AddressCollection<Address> Addresses { get; set; }
   ...
}

Lastly, I have an AddressControl class with a properties called CurrentAddressCollection of type AddressCollection<Address> and CurrentAddress of type Address.

public class AddressControl : System.Web.UI.UserControl
{
   public Address CurrentAddress { get; set; }
   public AddressCollection<Address> CurrentAddressCollection { get; set; }
}


Client1 c1 = new Client1();
AddressControl.CurrentAddress = c1.Addresses.GetFirstAddress(); // GetFirstAddress returns type of QuoteAddress
AddressControl.CurrentAddressCollection = c1.Addresses; // compile-time error

Client2 c2 = new Client2 ();
AddressControl.CurrentAddress = c2.Addresses.GetFirstAddress(); // GetFirstAddress returns type of Address
AddressControl.CurrentAddressCollection = c2.Addresses; // no problems
Pavel
  • 704
  • 11
  • 25
  • cause `QuoteAddress` isn't same as `Address`. Co-variance in classes are not supported – Rahul Oct 11 '17 at 22:46
  • But by definition of inheritance, a QuoteAddress is an Address. – Pavel Oct 11 '17 at 22:47
  • what is type of `c1.Addresses`? I suppose its type of `AddressCollection
    `
    – M.kazem Akhgary Oct 11 '17 at 22:47
  • read about `Covariance` in Generics – Rahul Oct 11 '17 at 22:48
  • @M.kazemAkhgary c1.Addresses is of type AddressCollection – Pavel Oct 11 '17 at 22:50
  • It will work only if you convert `c1.Addresses` to `AddressCollection
    `
    – abatishchev Oct 11 '17 at 22:50
  • @abatishchev not sure how. I tried c1.Addresses.Cast
    () as AddressCollection
    but that just returns a null.
    – Pavel Oct 11 '17 at 22:52
  • @Pavel does your collection in `Client1` have to be always in sync with `CurrentAddressCollection`? that is when you change collection in `Client1` do you expect `CurrentAddressCollection` to change as well? – M.kazem Akhgary Oct 11 '17 at 22:54
  • @M.kazemAkhgary yes. More importantly, the other way around. AddressControl is a Web UserControl where users can add/remove addresses. When they add/remove address from CurrentAddressCollection, the client's Addresses also need to see these changes. – Pavel Oct 11 '17 at 22:55
  • if user should be able to`add/remove` on `AddressControl`'s collection then `covariance` wont help you here. you need a collection adapter that will be simply a wrapper around `AddressCollection
    ` and filters items to `QuoteAddress`
    – M.kazem Akhgary Oct 11 '17 at 22:58
  • @M.kazemAkhgary My understanding is that this wrapper will do casting behind the scenes, but I'm still struggling with the basic concept of converting from a collection of QuoteAddress to collection of Address. – Pavel Oct 11 '17 at 23:04
  • converting a collection to other type requires copying from the main collection to new collection and convert each item. in that case,copied collection will have different reference of main collection, they become completely separate collections. so if you change new collection, changes wont reflect main one (or viceversa). on the other hand, covariance doesn't copy, it will cast, but it will be a cast into a read only interface so you can not change collection with interface. you got it pretty right. wrapper has main collection underneath, but will only show you items that are of type address – M.kazem Akhgary Oct 11 '17 at 23:10
  • Ideally, AddressControl's CurrentAddressCollection property would look like this instead: public AddressCollection CurrentAddressCollection { get; set; } But this is not allowed, the type or namespace name 'T' could not be found. – Pavel Oct 11 '17 at 23:10
  • (And for your edit - duplicates simply state that you can't do that if you need write access to collection - please re-read accepted answer https://stackoverflow.com/a/3720845/477420 or more lighthearted version https://stackoverflow.com/a/1817341/477420) – Alexei Levenkov Oct 11 '17 at 23:22

0 Answers0