【问题标题】:if the with keyword is bad (for C#), is this a nice alternative?如果 with 关键字不好(对于 C#),这是一个不错的选择吗?
【发布时间】:2008-12-21 08:39:22
【问题描述】:
var insInvoice = new NpgsqlCommand(
    @"INSERT INTO invoice_detail(
    invoice_id,
    invoice_detail_id,
    product_id,
    qty,
    price,
    amount)
    VALUES (
    :_invoice_id,
    :_invoice_detail_id,
    :_product_id,
    :_qty,
    :_price,
    :_qty * :_price)", c);


with(var p = insInvoice.Parameters)
{
    p.Add("_invoice_id", NpgsqlDbType.Uuid, 0, "invoice_id");
    p.Add("_invoice_detail_id", NpgsqlDbType.Uuid, 0, "invoice_detail_id");
    p.Add("_product_id", NpgsqlDbType.Uuid, 0, "product_id");
    p.Add("_qty", NpgsqlDbType.Integer, 0, "qty");
    p.Add("_price", NpgsqlDbType.Numeric, 0, "price");
}

kludge:

for(var p = insInvoice.Parameters; false;)
{       
    p.Add("_invoice_id", NpgsqlDbType.Uuid, 0, "invoice_id");
    p.Add("_invoice_detail_id", NpgsqlDbType.Uuid, 0, "invoice_detail_id");
    p.Add("_product_id", NpgsqlDbType.Uuid, 0, "product_id");
    p.Add("_qty", NpgsqlDbType.Integer, 0, "qty");
    p.Add("_price", NpgsqlDbType.Numeric, 0, "price");      
}

【问题讨论】:

  • 除非你很好地格式化它,否则不会。在每行代码前放置 4 个空格。

标签: c# syntactic-sugar


【解决方案1】:

由于您有一个具有正确形式的“添加”方法,您可以为参数使用集合初始化器:

var insInvoice = new NpgsqlCommand(sql)
{
    Parameters = 
    {
        { "_invoice_id", NpgsqlDbType.Uuid, 0, "invoice_id" },
        { "_invoice_detail_id", NpgsqlDbType.Uuid, 0, "invoice_detail_id" },
        { "_qty", NpgsqlDbType.Integer, 0, "qty" },
        { "_price", NpgsqlDbType.Numeric, 0, "price" }
    }
};

有关对象和集合初始化器的更多信息,您可以免费下载C# in Depth 的第 8 章。

【讨论】:

  • 在这种情况下绝对是我的首选
【解决方案2】:

定义“p”变量的范围有什么意义?

在这种情况下,只需创建一个带有花括号的作用域并一起删除 with 语句,将“p”的变量声明移动到新作用域中。这样,“p”变量仅在花括号范围内可用。你今天就可以做到这一点,而不需要任何语法糖。不过,我不确定这是否有助于提高可读性,只需将大括号全部移除并仅使用变量即可。

//with(var p = insInvoice.Parameters)
{
  var p = insInvoice.Parameters;
  p.Add("_invoice_id", NpgsqlDbType.Uuid, 0, "invoice_id");
  p.Add("_invoice_detail_id", NpgsqlDbType.Uuid, 0, "invoice_detail_id");
  p.Add("_product_id", NpgsqlDbType.Uuid, 0, "product_id");
  p.Add("_qty", NpgsqlDbType.Integer, 0, "qty");
  p.Add("_price", NpgsqlDbType.Numeric, 0, "price");
}

【讨论】:

  • 在一般情况下,这当然可以。在这个 specific 案例(添加)中,集合初始化器(参见 Jon 的回答)甚至更好。
【解决方案3】:

我做过类似的事情:

var insInvoice = new NpgsqlCommand(...);
insInvoice.Parameters.With(p => {
    p.Add("_invoice_id", NpgsqlDbType.Uuid, 0, "invoice_id");
    ...
});

【讨论】:

    【解决方案4】:

    如果您真的有兴趣通过消除其中的噪音和“仪式”来将代码简化为更易读的内容,那么在您的示例中还有更大的鱼可炒。

    在这种情况下,结合使用扩展方法、一些静态只读元数据、参数数组等,您应该能够为该插入语句自动生成 SQL,而不必手动编写代码。为什么任何给定的插入看起来都比这更复杂:

    db.Insert(Invoices.Table,
          new Value(Invoices.ID, "{something-something}"),
          new Value(Invoices.Quantity, 52),
          /*... and so on*/);
    

    无需手动编写大型 SQL 插入。根据列名自动选择的参数名称。名称类型和大小信息都绑定在Invoices 的这些静态成员中,因此您不会弄错它们。在调用点彼此相邻指定的名称和值。这一切都可能是你的!

    可选地,以某种简洁的 XML 结构声明数据库的结构,并编写一个工具,从该 XML 生成两件事:1. 用于设置数据库的 DDL 和 2. 每个表及其列的 C# 元数据.现在要扩展 DB 结构,只需编辑 XML 并重新运行该工具,它就可以让您立即轻松地从代码访问架构。

    在不知不觉中,您已经拥有了自己的廉价又实惠的 Linq to SQL 预算版本!

    (显然这已经偏离了主题,但为什么不在今年圣诞节用一种简单的方式编写插入语句呢?)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多