developer
developer

Reputation: 7400

Is using "as" in C# a safe way of casting?

I am wondering if using the keyword "as" in the following code is a safe way (i.e. won't blow up) of casting in C#:

public void abc(ref Object dataSource)
{
    DataTable table = dataSource as DataTable;
}

Is there a safer way of casting?

Upvotes: 33

Views: 27197

Answers (11)

KallDrexx
KallDrexx

Reputation: 27803

It is a safe way to cast in the fact that it won't cause an exception. However, it can cause hidden bugs if you are not careful.

When using as, if the cast fails then the resulting variable is null. If you don't check for this then you will later get a NullReferenceException when you attempt to access the variable, and it will be less clear on why it's failing (e.g. is it null because the cast failed or did something else later cause it to be null)

Upvotes: 3

Justin Morgan
Justin Morgan

Reputation: 30715

It depends what you mean by "safe". Ask yourself which is safer: an appliance with a circuit breaker, or one built without it? The one without a fuse is more likely to finish washing your clothes, but it's also more likely to burn your house down.

As you probably know, there are two main ways to do explicit casting in C#:

foo = (MyType)myObject;    //Cast myObject to MyType or throw an error
foo = myObject as MyType;  //Cast myObject to MyType or set foo to null

The difference is that if the runtime doesn't know how to cast myObject as MyType, the first line will throw an exception, while the second will only set foo to null. This would happen if the object living in myObject isn't a MyType, or if there's no explicit cast to MyType from whatever myObject is.

So which one is safer? Well, if "safe" means "won't throw an exception if the cast is invalid," then the as form is safer. If the casting fails, (MyType)myObject will blow up immediately, but myObject as MyType will only blow up if you try to do something to foo that you can't do to null (such as calling foo.ToString()).

On the other hand, sometimes throwing an exception is the safest thing to do. If you have a bug in your code, you probably want to know right away. If myObject is always expected to be a MyType, then a failed cast means there's a bug somewhere. If you carry on as though the casting worked, then all of a sudden your program is working with garbage data! It might blow up further down the line, making debugging difficult, or - worse - it might never blow up at all, just quietly do things you didn't expect. That could cause all kinds of havoc.

So neither form is inherently safe or correct, they're just useful for different things. You would use the myObject as MyType form if:

  1. You don't know for sure what type myObject is
  2. You want to do something with myObject, but only if it's of type MyType
  3. myObject could be something other than MyType, and it won't mean there's a bug

One example is when you have a collection of different WebForm controls, and you want to clear all the TextBoxes among them:

foreach (var control in controls)
{
    var textbox = control as TextBox;
    if (textbox != null)
    {
        //Now we know it's a TextBox, so we know it has a Text property
        textbox.Text = string.Empty;
    }
}

This way, your TextBoxes get cleared out, and everything else gets left alone.

Upvotes: 20

Michael Burr
Michael Burr

Reputation: 340188

The difference between using as and a normal cast is that if the cast can't be performed (because the object isn't the right type), the as operator will return null. A normal cast will throw an exception.

So they're both "safe" - they just have different behaviors when the cast can't be successful.

Upvotes: 1

vcsjones
vcsjones

Reputation: 141598

It won't throw an exception, if that is what you mean by "safe". However, if the cast fails, table will be null.

DataTable table = dataSource as DataTable;

Does not throw an exception if the cast fails. Will be null instead.

DataTable table = (DataTable)dataSource;

Will throw an exception if the cast fails.

It's safe in that regard, however if it is possible for the cast to fail, then add a null check to handle it.

Upvotes: 4

Tim Rogers
Tim Rogers

Reputation: 21713

Depends what you're trying to do:

DataTable table = dataSource as DataTable;
if (table != null) ...

means "dataSource might be a DataTable and I'm going to check it's not null."

DataTable table = (DataTable) dataSource;

means "dataSource should definitely be a DataTable and something's badly wrong if it's not".

Upvotes: 2

Matt Davis
Matt Davis

Reputation: 46034

as won't blow up, but if the cast fails, the variable will be set to null. You need to check for that case.

DataTable table = dataSource as DataTable;
if (table == null)
{
    // handle case here.
}

Upvotes: 4

Esteban Araya
Esteban Araya

Reputation: 29664

If you use as, there won't be a runtime InvalidCastException, but table may be null, so you need to check for that.

Upvotes: 0

carlbenson
carlbenson

Reputation: 3207

It's safe in the sense that it will get the job done if dataSource can be casted as a DataTable. But if you are worried about it not casting successfully, you can first check if dataSource.GetType() is equal to the Type you are trying to cast it to.

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500055

It won't blow up... but that doesn't necessarily mean it's safe.

Typically when I use a cast for a reference conversion, it's because I really, really think that the execution-time type is the one I'm specifying. If it's not, that indicates a bug in my code - and I'd rather that manifested itself as an exception.

If you've got bad data in your system, then continuing as if everything was fine is the dangerous path, not the safe path. That's the way that as will take you, whereas a cast would throw an InvalidCastException, aborting whatever you're doing before you get the chance to cause mayhem with the bad data.

as is good if it's valid for the object not to be of the given type - if it doesn't indicate a bug. You almost always see the pattern of:

Foo x = y as Foo;
if (x != null)
{
    ...
}

See MSDN for more details about what as does.

Note also that you probably don't want to use ref in your method. See my article on parameter passing for more details. Most of the time if I see people using ref a lot, it's because they don't understand what it really means :)

Upvotes: 51

BrokenGlass
BrokenGlass

Reputation: 160852

DataTable table = dataSource as DataTable;

Using as will return null if the cast is unsuccessful, so no it won't blow up. - that means you will have to handle the case that table is null in the rest of your code though.

Upvotes: 5

Jordan Parmer
Jordan Parmer

Reputation: 37164

The 'as' operator won't throw an exception if the cast is invalid. It just returns null. The () approach will throw an exception. So to answer your question, it is the safest way.

Here is essentially the way you need to go about it:

if( x is MyType )
{
   MyType y = (MyType) x;
}

or

MyType y = x as MyType;
if( y != null )
{
   // Do stuff
}

Upvotes: 2

Related Questions