Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define my own LINQ construct in C#?

Tags:

c#

linq

I have a code like this:

class PacketDAO{
    //...
    public void UpdatePacketStatus(Guid packetID, Status status)
    {
        using (var ctx = new DataContext())
        {
            var packet = ctx.Packet.SingleOrDefault(p => p.PacketID == packetID);
            packet.Status = status;
            ctx.SubmitChanges();
        }
    }

    public void UpdatePacketTime(Guid packetID, DateTime? time)
    {
        using (var ctx = new DataContext())
        {
            var packet = ctx.Packet.SingleOrDefault(p => p.PacketID == packetID);
            packet.Time = time;
            ctx.SubmitChanges();
        }
    }
    //...
}       

We can notice some boring repetition in the code.

So, it would be nice to write a generic method Update in a way we can afford ourselves to write something like this:

packet.Update<Guid, Packet>(guid, p => p.Time = DateTime.Now);
packet.Update<Guid, Packet>(guid, p => p.Status = Status.Ok);

Tell me, please, is it possible to write such a method?

Which book can I learn that from?

(I have found only one close example: http://msdn.microsoft.com/en-us/library/cc981895.aspx, but it is not clear enough how to derive my Update method from that)

Thank you.

UPD.

Ok, Jon Skeet tells there's something wrong in the question, and I agree, that my calls should look different, I think these calls are possible:

packet.Update<Packet>(p => p.packetID == guid, p => p.Time = DateTime.Now);
packet.Update<Packet>(p => p.packetID == guid, p => p.Status = Status.Ok);
like image 363
gentlenub Avatar asked Mar 31 '12 12:03

gentlenub


1 Answers

Lets start by writing an ordinary helper function. This has nothing to do with LINQ.

public static void UpdatePacket(Guid packetID, Action<Packet> update)
{
    using (var ctx = new DataContext())
    {
        var packet = ctx.Packet.SingleOrDefault(p => p.PacketID == packetID);
        update(packet);
        ctx.SubmitChanges();
    }
}

So you see, you can use the update-delegate to extract the only small piece of code which is different for each call. The rest is the same, and now we have it centralized and reusabe.

You can also make the method generic:

public static void UpdatePacket<TEntity>(Expression<Func<TEntity, bool>> filter, Action<TEntity> update)
{
    using (var ctx = new DataContext())
    {
        var e = ctx.GetTable<TEntity>().Single(filter);
        update(e);
        ctx.SubmitChanges();
    }
}

If you want to have the filter automated, you need to use the Expression and reflection API to construct the filter expression. The code for that is a little longer.

like image 183
usr Avatar answered Oct 17 '22 17:10

usr