Search code examples
c#loopsrefactoringsentinelnull-check

How to write this sentinel loop having a null check in a cleaner, shorter and efficient way?


I am using null as a sentinel/trip value to break out of foreach:

public static DataTable ExecuteQuery(string sql)
{
    var conn = new SqlConnection(EnvironmentVariables.GetDbConnectionString());
    var adapter = new SqlDataAdapter(sql, conn);
    var table = new DataTable();
    adapter.Fill(table);
    return table;
}
private VacantSummaryPage SelectPropertyFromDb(string sql)
{
    VacantProperty vacantProperty = null;
    List<VacantProperty> vacantProperties = GetProperties();
    foreach (DataRow row in SqlServer.ExecuteQuery(sql).Rows)
    {
        vacantProperty = vacantProperties.Find(v => v.GetTitle().Contains(row["PartialStreetAddress"].ToString()));
        if (vacantProperty != null) break;
    }
    vacantProperty.Select();
    return new VacantSummaryPage(driver);
}

What it does is once a vacantProperty is matched where it is then no longer null, break out of the loop and Select() that property.


Solution

  • You can write a "single line" instruction using a LINQ comprehension query (SQL-like syntax):

    private VacantSummaryPage SelectPropertyFromDb(string sql)
    {
      var query = from row in SqlServer.ExecuteQuery(sql).Rows.Cast<DataRow>()
                  from property in GetProperties()
                  where property.GetTitle().Contains(row["PartialStreetAddress"].ToString())
                  select property;
      vacantProperty = query.FirstOrDefault();
      if ( vacantProperty != null )
        vacantProperty.Select();
      return new VacantSummaryPage(driver);
    }
    

    Using only First will raise an exception if not found, so with FirstOrDefault we can control the not found case, unless exception control is preferred.

    Here the query itself is deferred, and it is evaluated when calling the First/FirstOrDefault or a ToList() for example.

    LINQ deferred (or immediate?) execution

    Deferred Execution of LINQ Query

    LINQ: Why is it called "Comprehension Syntax"

    Query Syntax and Method Syntax in LINQ (C#)

    LINQ Query Syntax (Comprehensive)

    LINQ Method Syntax (Lambda)

    Good to know

    TypedTableBase used by DataSet allow to directly implements IEnumerable<DataRow> and so also Typed DataSets.