Is it possible, in C# to create custom statements?
I would like to be able to create a new loop statement like this:
ifWhile(cond1, cond2) {
// code
}
Where if cond1 is true, the loop loops while cond2 is true.
I am trying to turn this tedious (and redundant) code:
if (rs.HasRows) {
while (rs.Read()) {
// do stuff
}
}
Into this more concise code:
ifWhile (rs.HasRows, rs.Read()) {
// do stuff
}
CodePudding user response:
No, you can't get that exact syntax, but you could use Func<T> and Action params to get something similar:
public static void IfWhile(bool cond1, Func<bool> cond2, Action code)
{
if (!cond1) return;
while(cond2())
code();
}
Usage:
IfWhile(rs.HasRows, () => rs.Read(), () =>
{
// Do stuff.
});
CodePudding user response:
You can't create new language features directly in C#, but you can create methods and/or extension methods that will get you closer.
Let's see how close we can get.
Here's what you're after:
ifWhile(cond1, cond2) {
// do stuff
}
And you want that to have the same semantics as this:
if (rs.HasRows) {
while (rs.Read()) {
// do stuff
}
}
What's important here is that rs.Read() gets called during each iteration of the while loop, so you need to use a Func<bool> rather than a bool for this second parameter.
You also can't just write a block of code, you need to run an Action.
So, as 41686d6564 says, you can do this:
public static void IfWhile(bool cond1, Func<bool> cond2, Action code)
{
if (!cond1) return;
while(cond2())
code();
}
And that allows you to write:
IfWhile(rs.HasRows, () => rs.Read(), () =>
{
// Do stuff.
});
It's close to what you initially wanted, but it's not ideal. I think the mess there is as bad, or, if not, worse, as simply repeating your code.
Here's an alternative that might be worth considering.
Let's flesh out what the rs code might look like:
public interface IRS
{
bool HasRows { get; }
bool Read();
IRow CurrentRow { get; }
}
public interface IRow { }
Now, that gives us a alternative way to remove duplication. Let's create an extension method to wrap all of this into a simple call.
public static class Ext
{
public static void IfHasRowsReadAll(this IRS rs, Action<IRow> action)
{
if (rs.HasRows)
{
while (rs.Read())
{
action(rs.CurrentRow);
}
}
}
}
Now you can go ahead and write this code:
rs.IfHasRowsReadAll(r =>
{
// do stuff
});
The r that is passed through to the // do stuff code is the instance of IRow.
This is one option for how to simplify this code.
Finally, there is a final extension method that might even be a better alternative. Try this extension method:
public static IEnumerable<IRow> GetRowsOrEmpty(this IRS rs)
{
if (rs.HasRows)
{
while (rs.Read())
{
yield return rs.CurrentRow;
}
}
}
Now, you can write this:
foreach (IRow r in rs.GetRowsOrEmpty())
{
// do stuff
}
I think that most cleanly expresses your intent and now it can be easily used with the rest of the LINQ operators.
