Does it make sense to use as instead of a cast even if there is no null check?
Your understanding is true. That sounds like trying to micro-optimize to me. You should use a normal cast when you are sure of the type. Besides generating a more sensible exception, it also fails fast. If you're wrong about your assumption about the type, your program will fail immediately and you'll be able to see the cause of failure immediately rather than waiting for a NullReferenceException
or ArgumentNullException
or even a logical error sometime in the future. In general, an as
expression that's not followed by a null
check somewhere is a code smell.
On the other hand, if you are not sure about the cast and expect it to fail, you should use as
instead of a normal cast wrapped with a try-catch
block. Moreover, use of as
is recommended over a type check followed by a cast. Instead of:
if (x is SomeType)
((SomeType)x).SomeMethod();
which generates an isinst
instruction for the is
keyword, and a castclass
instruction for the cast (effectively performing the cast twice), you should use:
var v = x as SomeType;
if (v != null)
v.SomeMethod();
This only generates an isinst
instruction. The former method has a potential flaw in multithreaded applications as a race condition might cause the variable to change its type after the is
check succeeded and fail at the cast line. The latter method is not prone to this error.
The following solution is not recommended for use in production code. If you really hate such a fundamental construct in C#, you might consider switching to VB or some other language.
In case one desperately hates the cast syntax, he/she can write an extension method to mimic the cast:
public static T To<T>(this object o) { // Name it as you like: As, Cast, To, ...
return (T)o;
}
and use a neat[?] syntax:
obj.To<SomeType>().SomeMethod()
Casting vs using the 'as' keyword in the CLR
The answer below the line was written in 2008.
C# 7 introduced pattern matching, which has largely replaced the as
operator, as you can now write:
if (randomObject is TargetType tt)
{
// Use tt here
}
Note that tt
is still in scope after this, but not definitely assigned. (It is definitely assigned within the if
body.) That's slightly annoying in some cases, so if you really care about introducing the smallest number of variables possible in every scope, you might still want to use is
followed by a cast.
I don't think any of the answers so far (at the time of starting this answer!) have really explained where it's worth using which.
Don't do this:
// Bad code - checks type twice for no reason
if (randomObject is TargetType)
{
TargetType foo = (TargetType) randomObject;
// Do something with foo
}Not only is this checking twice, but it may be checking different things, if
randomObject
is a field rather than a local variable. It's possible for the "if" to pass but then the cast to fail, if another thread changes the value ofrandomObject
between the two.If
randomObject
really should be an instance ofTargetType
, i.e. if it's not, that means there's a bug, then casting is the right solution. That throws an exception immediately, which means that no more work is done under incorrect assumptions, and the exception correctly shows the type of bug.// This will throw an exception if randomObject is non-null and
// refers to an object of an incompatible type. The cast is
// the best code if that's the behaviour you want.
TargetType convertedRandomObject = (TargetType) randomObject;If
randomObject
might be an instance ofTargetType
andTargetType
is a reference type, then use code like this:TargetType convertedRandomObject = randomObject as TargetType;
if (convertedRandomObject != null)
{
// Do stuff with convertedRandomObject
}If
randomObject
might be an instance ofTargetType
andTargetType
is a value type, then we can't useas
withTargetType
itself, but we can use a nullable type:TargetType? convertedRandomObject = randomObject as TargetType?;
if (convertedRandomObject != null)
{
// Do stuff with convertedRandomObject.Value
}(Note: currently this is actually slower than is + cast. I think it's more elegant and consistent, but there we go.)
If you really don't need the converted value, but you just need to know whether it is an instance of TargetType, then the
is
operator is your friend. In this case it doesn't matter whether TargetType is a reference type or a value type.There may be other cases involving generics where
is
is useful (because you may not know whether T is a reference type or not, so you can't use as) but they're relatively obscure.I've almost certainly used
is
for the value type case before now, not having thought of using a nullable type andas
together :)
EDIT: Note that none of the above talks about performance, other than the value type case, where I've noted that unboxing to a nullable value type is actually slower - but consistent.
As per naasking's answer, is-and-cast or is-and-as are both as fast as as-and-null-check with modern JITs, as shown by the code below:
using System;
using System.Diagnostics;
using System.Linq;
class Test
{
const int Size = 30000000;
static void Main()
{
object[] values = new object[Size];
for (int i = 0; i < Size - 2; i += 3)
{
values[i] = null;
values[i + 1] = "x";
values[i + 2] = new object();
}
FindLengthWithIsAndCast(values);
FindLengthWithIsAndAs(values);
FindLengthWithAsAndNullCheck(values);
}
static void FindLengthWithIsAndCast(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int len = 0;
foreach (object o in values)
{
if (o is string)
{
string a = (string) o;
len += a.Length;
}
}
sw.Stop();
Console.WriteLine("Is and Cast: {0} : {1}", len,
(long)sw.ElapsedMilliseconds);
}
static void FindLengthWithIsAndAs(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int len = 0;
foreach (object o in values)
{
if (o is string)
{
string a = o as string;
len += a.Length;
}
}
sw.Stop();
Console.WriteLine("Is and As: {0} : {1}", len,
(long)sw.ElapsedMilliseconds);
}
static void FindLengthWithAsAndNullCheck(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int len = 0;
foreach (object o in values)
{
string a = o as string;
if (a != null)
{
len += a.Length;
}
}
sw.Stop();
Console.WriteLine("As and null check: {0} : {1}", len,
(long)sw.ElapsedMilliseconds);
}
}
On my laptop, these all execute in about 60ms. Two things to note:
- There's no significant difference between them. (In fact, there are situations in which the as-plus-null-check definitely is slower. The above code actually makes the type check easy because it's for a sealed class; if you're checking for an interface, the balance tips slightly in favour of as-plus-null-check.)
- They're all insanely fast. This simply will not be the bottleneck in your code unless you really aren't going to do anything with the values afterwards.
So let's not worry about the performance. Let's worry about correctness and consistency.
I maintain that is-and-cast (or is-and-as) are both unsafe when dealing with variables, as the type of the value it refers to may change due to another thread between the test and the cast. That would be a pretty rare situation - but I'd rather have a convention which I can use consistently.
I also maintain that the as-then-null-check gives a better separation of concerns. We have one statement which attempts a conversion, and then one statement which uses the result. The is-and-cast or is-and-as performs a test and then another attempt to convert the value.
To put it another way, would anyone ever write:
int value;
if (int.TryParse(text, out value))
{
value = int.Parse(text);
// Use value
}
That's sort of what is-and-cast is doing - although obviously in a rather cheaper way.
What's the point in using is followed by as instead of as followed by a null check in C#?
To answer your actual question: Experience and habit.
Before the inclusion of the as
keyword in .Net 2.0, the only way to safely determine if an object could be cast to a specific type/interface was with the is
keyword.
So, people got in the habit of using is
before attempting an explicit cast in order to avoid unnecessary exceptions. This led to the pattern you have second in your list of samples:
if(whatever is IDisposable) //check
{
((IDisposable)whatever).Dispose(); //cast - won't fail
}
Then, we got the safe-cast as
keyword. I would guess that most people, when they first started using as
, continued to use the familiar pattern, but replaced the direct cast with a safe-cast, and their pattern of choice morphed into your example 1. (I know I did this for awhile.)
if(whatever is IDisposable)
{
(whatever as IDisposable).Dispose();
}
Eventually, many or most either realized on their own, or were instructed by fxCop or CodeAnalysis that the 'proper' pattern is your example 3:
IDisposable whateverDisposable = whatever as IDisposable;
if(whateverDisposable != null )
{
whateverDisposable.Dispose();
}
Certainly there are some floating around who are at the example 1 stage still and haven't yet 'evolved' their pattern to your example 3 for some reason, or others who are still just using the good-old time-proven pattern of using is
followed by a direct cast.
is' versus try cast with null check
Because there's only one cast. Compare this:
if (myObj.myProp is MyType) // cast #1
{
var myObjRef = (MyType)myObj.myProp; // needs to be cast a second time
// before using it as a MyType
...
}
to this:
var myObjRef = myObj.myProp as MyType; // only one cast
if (myObjRef != null)
{
// myObjRef is already MyType and doesn't need to be cast again
...
}
C# 7.0 supports a more compact syntax using pattern matching:
if (myObj.myProp is MyType myObjRef)
{
...
}
No Exception while type casting with a null in java
You can cast null
to any reference type without getting any exception.
The println
method does not throw null pointer because it first checks whether the object is null or not. If null then it simply prints the string "null"
. Otherwise it will call the toString
method of that object.
Adding more details: Internally print methods call String.valueOf(object)
method on the input object. And in valueOf
method, this check helps to avoid null pointer exception:
return (obj == null) ? "null" : obj.toString();
For rest of your confusion, calling any method on a null object should throw a null pointer exception, if not a special case.
Using an is check when with an explicit cast
FxCop issues Warning CA1800 in the first scenario (and not only when using as
, but also when using an unchecked cast) as both is
and the actual casts require certain type checking operations to determine whether the cast is successful or whether to throw an InvalidCastException
.
You might save a few operations by just using as
once and then checking the result for null
if you are going to use the cast value anyway, rather than checking explicitly with is
and then casting anew.
Why or why not use instanceof to check if not null
That depends on what you are actually checking
If you just want to know whether the reference is
null
, usex == null
and nothing elseIf you want to know whether a particular reference is not
null
and points to an instance of typeFoo
you may usex instanceof Foo
as it implies being notnull
But if the compile-time type of the reference is already
Foo
, you know that the instance is of typeFoo
when it is non-null
, therefore the first bullet applies in this case; you just want to test fornull
. This is the case in your updated question’s example, the reference already has the compile-time typeView
.If you want to know whether a type cast
(Foo)x
will succeed, you may usex == null || x instanceof Foo
as the type cast will also succeed whenx
isnull
(however, you should think twice whether you really want to acceptnull
s, even if the type cast will be successful)
What's the use of casting NULL to SomeType* in C++?
What's the use of casting NULL to SomeType* in C++?
SomeClass* someClassPtr = static_cast<SomeClass*>(NULL);
The cast has no effect in this context.
However more generally, it does make sense in some other context where overloading is involved:
void stupidly_overloaded_function(int);
void stupidly_overloaded_function(SomeClass*);
void stupidly_overloaded_function(SomeOtherClass*);
stupidly_overloaded_function(NULL);
which function gets called? It actually depends on the definition of NULL
. Either it calls the int
overload, or compilation fails due to ambiguity.
A cast can disambiguate the call:
stupidly_overloaded_function(static_cast<SomeClass*>(NULL));
I think this is a significant reason for introducing nullptr
. Although even nullptr
cannot deal with multiple different pointer overloads, it does disambiguate between integers:
void not_quite_as_silly_overload(int);
void not_quite_as_silly_overload(SomeClass*);
not_quite_as_silly_overload(NULL); // might call either overload
not_quite_as_silly_overload(nullptr); // unambiguously calls the pointer overload
Another case in C is macros involved with sizes of objects, such as the container_of
macro from the Linux kernel:
define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
Here, just 0 is used instead of NULL
. I think that this could be implemented in C++ without the cast, but only using declval
which was introduced in C++11.
Is this simply old-style (or even C-style) code from before there was nullptr?
No, there was no universal style for such redundant casts. Your example has no overloading, so the above case does not apply to it.
Is/was casting NULL necessary for other things than down-/upcasting when working with inheritance?
No, it was (and still is in the case of different pointer overloads) necessary for overload resolution.
What's the point of As keyword in C#
They aren't two system of casting. The two have similar actions but very different meanings. An "as" means "I think this object might actually be of this other type; give me null if it isn't." A cast means one of two things:
I know for sure that this object actually is of this other type. Make it so, and if I'm wrong, crash the program.
I know for sure that this object is not of this other type, but that there is a well-known way of converting the value of the current type to the desired type. (For example, casting int to short.) Make it so, and if the conversion doesn't actually work, crash the program.
See my article on the subject for more details.
https://ericlippert.com/2009/10/08/whats-the-difference-between-as-and-cast-operators/
Using as and expecting a null return
Yes, it's the right way to do it (considering "applying changes" will need to use the cast result).
However, if you are not going to use the cast return value, you can simply use is
.
Using is
and then casting again with the cast operator (parenthesis) is frowned upon.
Related Topics
How Do Prefix (++X) and Postfix (X++) Operations Work
Is Ruby's Code Block Same as C#'s Lambda Expression
Itextsharp Insert Text to an Existing PDF
Is There a Built-In Method to Compare Collections
Read from Location on Console C#
Change Desktop Wallpaper Using Code in .Net
How to Read and Write from the Serial Port
Invalid Length for a Base-64 Char Array
Updating Gui (Wpf) Using a Different Thread
Good Gethashcode() Override for List of Foo Objects Respecting the Order
Sharing Memory Between Two Applications
Call Ruby or Python API in C# .Net
How to Write an Async Method with Out Parameter
How to Instantiate a Class Given Its String Name
Use Own Icomparer<T> with Linq Orderby
How to Check If Wpf Is Currently Executing in Design Mode or Not
Is Using a Mutex to Prevent Multiple Instances of the Same Program from Running Safe