The answer below was written years ago and updated over time. As of C# 7, you can use pattern matching:
if (animal is Dog dog)
{
// Use dog here
}
Note that dog
is still in scope after the if
statement, but isn't definitely assigned.
No, there isn't. It's more idiomatic to write this though:
Dog dog = animal as Dog;
if (dog != null)
{
// Use dog
}
Given that "as followed by if" is almost always used this way, it might make more sense for there to be an operator which performs both parts in one go. This isn't currently in C# 6, but may be part of C# 7, if the pattern matching proposal is implemented.
The problem is that you can't declare a variable in the condition part of an if
statement1. The closest approach I can think of is this:
// EVIL EVIL EVIL. DO NOT USE.
for (Dog dog = animal as Dog; dog != null; dog = null)
{
...
}
That's just nasty... (I've just tried it, and it does work. But please, please don't do this. Oh, and you can declare dog
using var
of course.)
Of course you could write an extension method:
public static void AsIf<T>(this object value, Action<T> action) where T : class
{
T t = value as T;
if (t != null)
{
action(t);
}
}
Then call it with:
animal.AsIf<Dog>(dog => {
// Use dog in here
});
Alternatively, you could combine the two:
public static void AsIf<T>(this object value, Action<T> action) where T : class
{
// EVIL EVIL EVIL
for (var t = value as T; t != null; t = null)
{
action(t);
}
}
You can also use an extension method without a lambda expression in a cleaner way than the for loop:
public static IEnumerable<T> AsOrEmpty(this object value)
{
T t = value as T;
if (t != null)
{
yield return t;
}
}
Then:
foreach (Dog dog in animal.AsOrEmpty<Dog>())
{
// use dog
}
1 You can assign values in if
statements, although I rarely do so. That's not the same as declaring variables though. It's not terribly unusual for me to do it in a while
though when reading streams of data. For example:
string line;
while ((line = reader.ReadLine()) != null)
{
...
}
These days I normally prefer to use a wrapper which lets me use foreach (string line in ...)
but I view the above as a pretty idiomatic pattern. It's usually not nice to have side-effects within a condition, but the alternatives usually involve code duplication, and when you know this pattern it's easy to get right.
null
is cast tofalse
. So, if the result of the assignment is null, the statement evaluates tonull
which is then cast tofalse
. That is why in some languages you can useif(var) {...}
to execute code only if that variable is non-null. Generally, assigning to variables in anif
statement is poo-pooed because it looks like a common error (typing=
instead of==
). One used to be able to gain some (small) performance benefit from using an assignment in anif
block, but many modern compilers will do optimizations like this for you. – Pablopabonif($var = <expression>)
and then$var
is casted tobool
and used for the check.$var
is than also available in the scope where theif
statement is. – Accumulatornull
!=false
in C#; C# only allows actual bools or things implicitly convertible to bools inif
conditions. Neither nulls nor any of the integer types are implicitly convertible to bools. – Casperif
clause, I wrap everything is a scope, which is more verbose, and almost as ugly than thefor(...)
solution of Jon Skeet, markedEVIL EVIL EVIL
for some reason... Aaah, sweet Inquisition... ^_^ ... – Scat