如何在C#中定义自己的LINQ构造?

时间:2012-03-31 12:44:20

标签: c# linq

我有这样的代码:

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();
        }
    }
    //...
}       

我们可以注意到代码中有些无聊的重复。

因此,以一种我们可以负担得起的方式编写一个通用的方法Update会很好:

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

请告诉我,是否可以编写这样的方法?

我可以从中学到哪本书?

(我发现只有一个接近的例子:http://msdn.microsoft.com/en-us/library/cc981895.aspx,但是不清楚如何从中推导出我的Update方法。

谢谢。

UPD。

好的,Jon Skeet告诉我这个问题有问题,我同意,我的电话应该看起来不一样,我认为这些电话是可能的:

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

1 个答案:

答案 0 :(得分:10)

让我们从编写一个普通的帮助函数开始。这与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();
    }
}

所以你看,你可以使用update-delegate来提取每个调用不同的唯一一小段代码。其余的是相同的,现在我们将它集中并重新使用。

您还可以使方法通用:

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();
    }
}

如果要使过滤器自动化,则需要使用Expression和reflection API来构造过滤器表达式。这段代码要长一点。