Reputation: 1725
I'm trying to keep to the DRY principle in C#, and I was wondering if it's possible to access the argument checks in an if
block. For example, would the below be possible?
if (foo == true || bar == false)
{
if (check0)
{
//foo is true
}
if (!check1)
{
//bar is false
}
}
I was also wondering if it's possible to do this, to keep the scope clean?:
if (var foo = runTimeAccessedVariable == "bar")
{
//we now have the runtime generated variable.
}
//but it doesn't exist here
Upvotes: 3
Views: 665
Reputation: 2300
You can actually. You can use (extension) methods like this:
// For first case.
public static void If(this Lazy<bool>[] checks, Predicate<Lazy<bool>[]> ifCondition, Action<Lazy<bool>[]> ifAction) {
if (ifCondition(checks)) ifAction(checks);
}
// For second case.
public static void If(this object[] variables, Predicate<object[]> ifCondition, Action<object[]> ifAction) {
if (ifCondition(variables)) ifAction(variables);
}
And use of it would look like this:
// First case.
new[] { new Lazy<bool>(() => foo == true), new Lazy<bool>(() => bar == false) }.
If(checks => checks[0].Value || checks[1].Value, checks => {
if (checks[0].Value) {
//foo is true
}
if (!checks[1].Value) {
//bar is false
}
});
// Second case.
new[] { "bar" }.If(variables => (string)variables[0] == "bar", variables => {
//we now have the runtime generated variable.
});
This will limit the scope of those temporary values. However, this does not provide any check for whether you actually using checks
or variables
in the right way. And it would be harder to debug if something goes wrong then simple if
statement.
This could also be extended to accept Func
instead of Action
that your If
method could return
result as well. And it is possible to even add ElseIf
and Else
methods to chain with If
method (to mimic all if
statement behavior).
Upvotes: 0
Reputation: 21490
The scope and reuse can both be trivially solved by using a pair of brackets to define a new scope;
pulic void MyFunc()
{
// do stuff here in the scope of MyFunc
{
// create child scope with new scoping rules and declare control variables
var fooTrue = foo == true;
var barFalse = bar== false;
if (fooTrue || barFalse)
{
if (fooTrue)
{
//foo is true
}
if (barFalse)
{
//bar is false
}
}
}
// stuff here cannot access fooTrue, barFalse.
}
This stops the variables from 'leaking out' of this part of the function. There is a small semantic difference because the var barFalse
line isn't shortcut, but it seems from your example that you'll probably need to test it anyway so it shouldn't be a concern.
Upvotes: 2
Reputation: 32780
Answering you second question, no it is not possible to declare a variable in this way. The only similar alternative is to use { }
to create your own local scope and declare the local variable before the if
statement:
{
bool foo;
if (foo = runTimeAccessedVariable == "bar")
{
}
}
In any case I'm not really sure what the benefits of this approach are. If you are insde the if
statement, you already know foo
is true
, what is the use of having the scoped local?
Concerning your first question, I'd just push back on the whole approach. You are basically using an if
statement based on a boolean expression made up of two or more conditions. Then, once inside the if
statement you are discerning between what boolean condition is met or not. Also, you could have the case of an uninitialized variable, because check1
is not guaranteed to run.
I'd rewrite that completely and by-pass the need of any locally scoped variables:
Work is independent for each condition:
if (foo)
{
//whatever
}
else if (bar)
{
//whatever
}
There is common work for both conditions:
if (foo)
{
//whatever
if (bar)
{
//whatever
}
}
Both would be semantically equivalent to what you are proposing.
Upvotes: 0
Reputation: 172448
Nope, it's not possible. In fact, since you use the short-circuiting ||
operator, the second check might not even be evaluated.
Obviously, you can work around it as follows:
var fooIsTrue = (foo == true);
var barIsFalse = (bar == false);
if (fooIsTrue || barIsFalse)
{
...
}
Note that this changes the behaviour of your code, since barIsFalse
is always evaluated.
Upvotes: 4