views:

165

answers:

7

I have a class Booking

public class Booking
    {
        public int Id { get; set; }

        public string From { get; set; }

        public string To { get; set; }
    }

I create a List bookings with the help of linq and I want some mechanism with which I want to autogenerate the 'Id' property to increment by 1.

I.e. if the List bookings contains 10 Booking object then the first object's Id = 1, second Id = 2 and so one...

any suggestion

+3  A: 

The following will give you a list of NEW bookings with the index projected into your ID property. You could probably do something similar to this to update the existing list with the index...

var myBookings = myExistingListOfTen.Select((b, index) => new Booking
                 {
                     Id = index + 1, 
                     From=b.From, 
                     To=b.To
                 });
Scott Ivey
This way you lose the reference and you do unnessecary object instantiation.
Dykam
Yes, you do. OP asked for neither of those requirements though...
Scott Ivey
For me, this is the best answer so far.
jpbochi
True. But there are better solutions.
Dykam
Yes, i agree there are too. There are times when something like this can be used, but those cases are pretty small compared to when it probably shouldn't be used.
Scott Ivey
its looks good to me and can you give me equivalent of the above sample code in LINQ, i.e. from booking in Bookingsselect new bla bla
Miral
My example is linq already. To get the index, you have to use the overloads of the select methods - so no way to do that in the query based example without leaving the select in there.
Scott Ivey
A: 

Not sure if I understand your question right, but you could always

ID = bookings.Select(b=>b.ID).Max()+1;

Not sure if that's such a good idea (it won't be uber performant).

borisCallens
The performance would be disastrous :P. O(n^2)
Dykam
+3  A: 

Not nice, but it will work. The trick is to use the overload providing the index of the item.

list = list.Select((item, index) => { item.Id = index; return item; });

This will update the existing bookings, but you could also select a new instance with the id set and avoid this ugly return at the cost of duplicating the bookings and losing the references as Scott Ivey suggests. And of course you have to add one if you want one-based ids.

I find it a bit strange to generate ids this way, too, but it might be a acceptable solution if you get a list of new bookings without id and want to generate them. In this case the ids should obviously not start with zero or one, but the largest already assigned id plus one.

Daniel Brückner
+1 - good answer Daniel.
Scott Ivey
+1  A: 

To be able to do the following:

bookings.ForEach((booking, index) => booking.Id = index + 1);

You need to place to following snippet somewhere in a static class:

public static IEnumerable<T> ForEach<T>(
        this IEnumerable<T> source,
        Action<T, int> action)
    {
     int index = 0;
        foreach (T element in source) {
      action(element, index++);
     }
    }
    return source;
}

Ofcourse the following will work too:

int index = 0;
foreach (var booking in bookings) {
    booking.Id = ++index;
}
Dykam
+1  A: 
public class Booking
{
    private static int BookingCount = 1;

    public Booking()
    {
       Id = BookingCount++;
    }

    public int Id { get; set; }

    public string From { get; set; }

    public string To { get; set; }
}
DanDan
That is bad practice, ins't it? What is the questioner wants two collections?
Dykam
this will create a global counter... and also, i will suggest using Interlocked for thread safety
Bogdan_Ch
+4  A: 

Surely if it is a property on the object you want the value to be consistent from invocation to invocation. Booking 'A' shouldn't have a different id depending on where it exists in the list. If you are simply wanting the index of the item in the list, don't store it as a property of the item, but derive it from its position in the list.

tvanfosson
voted for this . all other suggestion do not take into account that bookings can be not only added but also removed from the collection. though, question is not clear enough.
Bogdan_Ch
A: 

Although I agree with @tvanfosson (+1), if you really want to keep an ID in Booking I think that this should be setted upon the construction of Booking. You could have something like a Booking Context where each context would create bookings with serial IDs:

    public class Booking
    {
        protected Booking() { }
        public int Id { get; set; }

        public string From { get; set; }

        public string To { get; set; }
    }

    public class BookingContextFactory
    {
        private int count;

        public BookingContextFactory() : this(0) { }
        public BookingContextFactory(int startValue) 
        {
            count = startValue;
        }

        public Booking CreateBooking(string from, string to)
        {
            return new InternalBooking { Id = count++, From = from, To = to };
        }

        private class InternalBooking : Booking
        {
            public InternalBooking() : base() { }
        }
    }
bruno conde