【问题标题】:How can I modify this C# code so that Visual Studio recognizes that I'm not an idiot?如何修改此 C# 代码,以便 Visual Studio 识别出我不是白痴?
【发布时间】:2023-03-23 12:37:02
【问题描述】:

我有 3 行可以运行

int selectedOrgId; 

foreach (Organization o in PD.orgs)
    if (o.orgname == selectedOrgName)
         selectedOrgId = o.orgid;

PD.cats.InsertOnSubmit(new Category {
    orgid = selectedOrgId,
    catname = newCatName
});

在我的程序上下文中,保证中间行,即循环,为selectedOrgId 设置一个值。但是,Visual Studio 会标记最后一行,因为

使用未分配的局部变量“selectedOrgId”

除了

还有什么方法可以解决这个问题
int selectedOrgId = 69; 

foreach (Organization o in PD.orgs)
    if (o.orgname == selectedOrgName)
         selectedOrgId = o.orgid;

PD.cats.InsertOnSubmit(new Category {
    orgid = selectedOrgId,
    catname = newCatName
});

??????

虽然它有效,但它似乎是一个不雅的解决方案,因为它涉及一个幻数。我想知道解决这个问题的正确 C# 风格。

编辑:

看看这里的一些讨论,我应该指定数据库中只有这样的orgid。我的foreach 声明应该这样写

foreach (Organization o in PD.orgs)
{
    if (o.orgname == selectedOrgName)
    {
         selectedOrgId = o.orgid;
         break;
    }
 }

感谢您向我展示了一些可以更好地完成这件事的方法!

【问题讨论】:

  • 任何开发人员都可以做出的大胆声明
  • Visual Studio 对您的程序上下文一无所知...
  • This 声明最佳实践是让它失败,然后以错误的值静默运行。我建议,如果您想在循环后 selectOrgId 为 0 时执行异常。这将使您的代码更加有意。
  • 它抱怨的原因是因为selectedOrgId 可能永远不会被设置,因为第 2 行的If 语句。如果它永远不会被设置,那么当你尝试使用它时它将有一个未初始化的值它在第 3 行,这可能会导致问题。您需要确保在所有代码路径上都设置了一个值,或者将您的逻辑更改为仅在该变量具有已知有效值时才使用该变量。恕我直言,Visual Studio 正确地警告您此代码。
  • @FiredfromAmazon.com that I'm not an idiot

标签: c# linq


【解决方案1】:

您似乎正在遍历一个集合,试图根据组织名称查找单个匹配值。您可以使用 LINQ 的 SingleOrDefault() 找到(最多)一个匹配项:

var selectedOrg = PD.orgs.SingleOrDefault(o => o.orgname == selectedOrgName);

如果找到值,则仅调用InsertOnSubmit()(否则,selectedOrg 将为空)

if (selectedOrg != null)
    PD.cats.InsertOnSubmit(new Category { orgid = selectedOrg.orgid, catname = newCatName });

【讨论】:

    【解决方案2】:

    如果 PD.orgs 中的任何值都不满足条件 o.orgname == selectedOrgName 会发生什么?然后selectedOrgId 将保持未初始化状态。

    但是,根据您的方法,以下代码可能更“优雅”:

    int selectedOrgId = PD.orgs.Single(o => o.orgname == selectedOrgName).orgid;
    PD.cats.InsertOnSubmit(new Category { orgid = selectedOrgId, catname = newCatName });
    

    请注意,您的代码会将selectedOrgId 设置为它的最后一个实例,而我的代码会假设只有一个实例存在。

    【讨论】:

    • 如果没有找到匹配项或找到多个匹配项,这也会引发异常。
    【解决方案3】:

    您可以使用int?

    int? selectedOrgId = null;
    
    foreach (Organization o in PD.orgs)
    {
        if (o.orgname == selectedOrgName)
        {
             selectedOrgId = o.orgid;
        }  
     }
    
     PD.cats.InsertOnSubmit(new Category 
     { 
            orgid = selectedOrgId,
            catname = newCatName 
     });
    

    【讨论】:

    • “int”有什么意义?并在您可以简单地将0分配给变量时为其分配null?此外,Category.orgid 不能为空。
    • @MehrzadChehraz 因为您希望能够分辨 id 为 0 和未找到 id 之间的差异。 OP 从未显示 orgid 是什么。
    • @Mehrzad 0 可能是int 的有效值。而null在这种情况下表示“空值”,这是完全不同的。
    • @JasonWilczak 这绝对是一个很好的讨论,但这也是一个风格问题。尽管使用 LINQ 的其他答案与此解决方案一样好(甚至可能更好),但我认为在这种情况下使用可空对象没有任何问题。还是有可能的。
    • @YuvalItzchakov 至少你可以在答案中包含这个假设。实际上,每个人都在做出假设并给出答案。是的 OP 将有希望地使用答案。我放手了:D。
    【解决方案4】:

    这不是唯一的问题。您知道您会找到 1 个或多个匹配项,而编译器不会。

    但是“或更多”也是一个问题。代码只是不清楚你想要什么,这是根本原因。您有一个隐含的“最后一个获胜”策略。

    当您使用更符合要求的解决方案时,编译器问题会在没有任何技巧的情况下消失。

    没有 Linq:

    // int selectedOrgId; 
    
    foreach (Organization o in PD.orgs)
        if (o.orgname == selectedOrgName)
        {
           PD.cats.InsertOnSubmit(new Category {
             orgid = o.orgid,
             catname = newCatName
          }); 
          return;   // or break;
        }
    // shouldn't get here
    throw new ...
    

    还有 Linq

    Organization org =  PD.orgs.Single(o => o.orgname == selectedOrgName);
    PD.cats.InsertOnSubmit(new Category {
              orgid = selectedOrgId,
              catname = newCatName
           }); 
    

    Single(Predicate) 方法与您的问题非常吻合。当结果集有 != 1 个元素时,它会抛出。

    【讨论】:

    • selectedOrgId 只存在于循环内部,OP 想要它在外部
    • @JAT:不再有“圈外”,也不应该有。请仔细阅读。
    • 我试图理解,如果你不能在其他地方使用 int selectedOrgId = o.orgid; 有什么意义呢?
    • 你可以很容易地消除它,但我让它保持接近原始代码。真的没关系。
    • 如果您不打算在其他任何地方使用,请执行以下操作:PD.cats.InsertOnSubmit(new Category { orgid = o.orgid, catname = newCatName});
    【解决方案5】:

    编辑:OP 更改了问题以指定只能找到一个项目并且不需要多个解决方案,这里是选项 1a

    选项 1a - 单行 Linq 方法

    这提供了一个单行 linq 查询,它将过滤掉不必要的组织,获取单个项目并选择一个新的 Category 对象作为插入的参数。如果无法找到单个项目,此方法将引发异常,但这是明确的,根据您的问题应该发生什么。

    PD.cats.InsertOnSubmit(
        PD.orgs.Where(o=>o.orgname==selectedOrgName)
        .Single()
        .Select(o=>new Category { orgid = o.orgId, catname = newCatName })
    );
    

    选项 1b - 迭代过滤列表并执行工作

    这里的所有其他答案都建议使用 linq 并假设只会找到一条记录。为什么不只在循环中做所有事情并使用 linq 过滤结果?

    foreach (Organization o in PD.orgs.Where(o=>o.orgname==selectedOrgName)) 
    {
        PD.cats.InsertOnSubmit(new Category { orgid = o.orgId, catname = newCatName });
    }
    

    这里的好处是没有 if 语句,它可以处理单个或多个案例。有一种方法可以在一行上完成并删除每个的显式并使用 List.ForEach (see the comparisons):

    PD.orgs.Where(o=>o.orgname==selectedOrgName).ToList()
    .ForEach(o=>PD.cats.InsertOnSubmit(new Category { orgid = o.orgId, catname = newCatName }));
    

    选项 2 - 使用例外

    这将非常清楚您的代码意图是什么,并让 Visual Studio 知道您已经处理了这个问题。这个想法是让您的代码非常接近现在的方式:

    int selectedOrgId; 
    foreach (Organization o in PD.orgs) 
    {
        if (o.orgname == selectedOrgName) 
           selectedOrgId = o.orgid;
    }
    

    不过,此时我建议你使用异常,例如:

    if(selectedOrgId == 0) throw new InvalidDataException("Selected Org Id cannot be 0");
    PD.cats.InsertOnSubmit(new Category { orgid = selectedOrgId, catname = newCatName });
    

    【讨论】:

    • 但是你使用的是 Linq
    • @JAT 你是对的,我的手指离开了我。我编辑了文本以使我的观点更清楚。
    • @JAT:他不是说他不是。他是说,与其他暗示 Linq 的答案不同,他的账户发现了不止一条记录。
    • 喜欢这个主意。讨厌水平滚动。 :P
    • List.ForEach 不是 LINQ 方法。事实上,这是一种与 LINQ 的目标和编码风格大相径庭的方法。 “更多 LINQ”解决方案是使用 foreach,而不是 ForEach
    【解决方案6】:

    使用linq 选择带有selectedOrgName 的组织并获取orgid

    PD.cats.InsertOnSubmit(new Category { 
        orgid = PD.orgs.First(o => o.orgname == selectedOrgName).orgid, 
        catname = newCatName
    });
    

    假设selectedOrgName 将始终在PD.orgs 中,我根据变量名做出该假设;但是,如果情况并非总是如此,您可以执行以下操作:

    var selectedOrg = PD.orgs.FirstOrDefault(o => o.orgname == selectedOrgName);
    
    if (selectedOrg != null)
    {
        PD.cats.InsertOnSubmit(new Category { 
            orgid = selectedOrg.orgid, 
            catname = newCatName
        });
    }
    

    【讨论】:

      【解决方案7】:

      以下内容与您的代码完全相同,但如果您没有匹配的组织(您说不可能发生),它将引发异常:

      PD.cats.InsertOnSubmit(new Category { 
          orgid = PD.orgs.Last(o => o.orgname == selectedOrgName).orgid, 
          catname = newCatName
      });
      

      【讨论】:

        猜你喜欢
        • 2017-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-26
        • 2022-08-12
        • 2019-02-10
        相关资源
        最近更新 更多