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

gen*_*nub 7 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();
        }
    }
    //...
}       
Run Code Online (Sandbox Code Playgroud)

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

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

packet.Update<Guid, Packet>(guid, p => p.Time = DateTime.Now);
packet.Update<Guid, Packet>(guid, p => p.Status = Status.Ok);
Run Code Online (Sandbox Code Playgroud)

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

我可以从中学到哪本书?

(我发现只有一个接近的例子: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);
Run Code Online (Sandbox Code Playgroud)

usr*_*usr 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

所以你看,你可以使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 请注意,我们甚至没有使用扩展方法.这里不需要它.简单就足够简单. (4认同)
  • 您可以通过编辑来直接将其他信息添加到答案中,而不是将评论写入您自己的答案:) (2认同)