Tim said:
Reasonable behaviour is entirely dependent on its context. It's just a code
snippet so reasonable behaviour doesn't really come into it.
Well, sortof... often there is no reasonable alternative behaviour.
Whether to use "as" of (cast) depends on what behaviour should happen if
collection is not IEnumerable. If you expect the object to actually be
IEnumerable, use a cast. If you have some alternate action if it is not
IEnumerable, as is a very viable option for dispatch.
The must usefull use of as that i've seen if in Equals:
public override bool Equals(object o) {
Foo other = o as Foo;
if ( other == null )
return other;
// continue compare
}
or when you already know that the as conversion will yield non-null:
if ( x is Foo )
(x as Foo).f();
else if ( x is Bar )
(x as Bar).f();
...
C Style casting uses the castclass opcode which, as you know, throws an
exception if the type atop the stack is not of the desired type. The as
operator uses the isinst opcode instead, returning a null reference in the
event of the type atop the stack not being of the desired types.
How does the IL code come into consideration? This is about semantics.
There are other considerations of course - the as operator can't use
conversion operators, whereas the C style cast can. The C style cast is
slower than the as operator in success scenarios, and *much* slower than the
as operator in failure scenarios.
Slower? have you done any tests?
I have a test that shows almost exactly the same performance of the two
casts when successfull, with a *slight* edge to casting (less than 2%).
Certainly the difference between the performance of the operations is
nowhere near high enough to be of any consideration.
The semantics of operations is vastly more important that the
performance, atleast untill performance becomes a problem.
I have a saying i repeat when someone brings this, or foreach vs.
for+index or something other like that up:
"Syntax rarely change performance, but often changes correctness"
I guess the best place for the C style cast is when failure would indicate
an exceptional circumstance.
Yes, but I formulate that the other way around, "rather CastException
now than unexpected behaviour or NullException later". Of course, if you
really *can* do something with the object, even if it's not of the
expected type, using as is fine (and proper).
What I don't want to see is code like:
void f(object x) {
Foo y = x as y;
y.f();
}
Which discards the very usefull info that infact x was not convertible
to y, and instead generates a NullException.
or, the programmer who have heard "as" performs better than casting:
void f(object x) {
Foo y = x as y;
if ( y == null )
throw new SomeException()
}
or, even worse, the surprising semantics of
"default-do-nothing-to-be-flexible"
void f(object x) {
Foo y = x as y;
if ( y != null ) {
// fine and dandy, operations
...
} else {
// What can we do here? ignore
}
}
Which I have seen a few times. This clearly shows a spot where a cast
should have been used. Now, a callers type-mistake is silently ignored!