-1

I am wondering why I can not make casting in my ViewModel`s constructor:

public BookingsViewModel()
{
    IEnumerable<Booking> bookingsDB = repository.GetBookings();
    model = bookingsDB; //exception
}

It throws me an exception:

Cannot implicitly convert type System.Collections.Generic.IEnumerable<Library2.Models.Booking> to Library2.Models.Bookings. An explicit conversion exists (are you missing a cast?)

When GetBookings() looks like that:

public IEnumerable<Booking> GetBookings()
{
    var bookings = context.Bookings.
            Include(i => i.Book).
            Include(i => i.Reader).
            AsEnumerable().
            ToList();
    return bookings;
}

And Bookings model like that:

public class Bookings : IEnumerable<Booking>
{
    private List<Booking> bookingList = new List<Booking>();
    public void AddBooking(Booking booking)
    {
        bookingList.Add(booking);
    }
    public bool DeleteBooking(Booking booking)
    {
        return bookingList.Remove(booking);
    }
    public int BookingList
    {
        get
        {
            return bookingList.Count;
        }
    }
    public Booking this[int index]
    {
        get
        {
            return bookingList[index];
        }
    }
    public IEnumerator<Booking> GetEnumerator()
    {
        return bookingList.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Where is the problem if Bookings implements IEnumerable<Booking>? How to solve the problem?

GSerg
  • 76,472
  • 17
  • 159
  • 346
bakunet
  • 11
  • 1
  • 2
    `Bookings` is an `IEnumerable`. `List` is an `IEnumerable`. `List` is not `Bookings`. Where would a `List` get these `AddBooking()`, `DeleteBoocking()` etc from? – GSerg Feb 07 '19 at 09:54
  • 2
    So while every `Bookings` **is** an `IEnumerable`, not every `IEnumerable` is a `Bookings`. – MakePeaceGreatAgain Feb 07 '19 at 09:54

3 Answers3

2

There's hardly ever any need to implement IEnumerable<T> for collections in user code. See also Why not inherit from List<T>?. Doing so is probably the wrong approach for the problem you're trying to solve.

Now you have a variable Bookings model, where Bookings : IEnumerable<Booking>, and you want to assign an IEnumerable<Booking> to that variable - you can't. Just as that you can't assign an Animal instance to a Dog variable - the dog is an animal, but not every animal is a dog.

Either change the type of model to IEnumerable<Booking>, or change your approach altogether.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

You can't up-cast like that, Bookings != IEnumerable<Booking> even though Bookings implements IEnumerable<Booking>.

You can think of it like this, my car has a IDoors interface, my truck has a IDoors interface. However it makes no sense to call them the same, they just share the same doors contract. I can't make my truck into a car no matter how hard I try with a cast implicit or not, all I can do is say they share a similarity in doors.

halfer
  • 19,824
  • 17
  • 99
  • 186
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
0

The problem is in variable model

private Bookings model;

Although class model implements IEnumerable<Booking>, it is not (a parent of) the same class of the object returned by repository.GetBookings().

Compare this with:

class Person {...}
class Male : Person {...}
class Female : Person {...}

Person p = new Male();
Female f = p;

You can't just assign an object to an object of an unrelated class.

You need to write a converter that converts any sequence of Bookings into an object of class Bookings. The easiest way would be to add a constructor:

public Bookings(IEnumerable<Booking> bookings)
{
    this.bookingList = bookings.ToList();
}

Note: bookingList is a new list, containing the same elements as bookings. If you add a booking to your original list, it isn't added to your Bookings object and vice versa.

Other possible improvements: apparently you plan to store you bookings internally in a list. Why not implement IList<Booking>. With very little effort you add a lot of functionality

class Bookings : IList<Booking>, IReadonlyList<Booking>, IReadonlyCollection<Booking>
{
    public Bookings()
    {
        this.bookings = new List<Booking>();
    }

    public Bookings(IEnumerable<Booking> bookings)
    {
        this.bookings = bookings.ToList();
    }

    private readonly IList<Booking> bookings;

    public int Count => this.booking.Count;
    public void Add(Booking booking) {this.booking.Add(booking);}
    public void Remove(Booking booking) {this.booking.Remove(booking);}
    public IEnumerator<Booking> GetEnumerator() {return this.booking.GetEnumerator();}
    etc.
}

Note: In visual studio, if you right click on the IList<Bookin>, and select Quick-actions and refactoring, all functions will be implemented at once. You can even say that all these functions should use this.booking.

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116