Related
I've been reading up on SharePoint 2010 for work and I've noticed that many code examples I run into from books to instructional videos are cast SharePoint objects in a way I never knew existed in C# (and thought was VB exclusive):
SPWeb web = properties.Feature.Parent as SPWeb;
I'm so used to casting (outside of VB) this way (SPWeb)properties.Feature.Parent and was just curious if there was any particular reason most pieces on SharePoint I've encountered use the VB-esque casting notation.
as is called the safe cast operator in C#. There is a semantic difference between that and a normal cast. A safe cast will not throw an exception if the type cannot be cast; it will return null. A normal cast throws InvalidCastException if the type cannot be cast.
In other words, this code assigns null if Parent if not of type SPWeb:
SPWeb web = properties.Feature.Parent as SPWeb;
While the other version throws if Parent is not of the correct type:
SPWeb web = (SPWeb)properties.Feature.Parent;
The as operator can be quite useful if you don't know for sure that an object can be cast to the desired type - in this case it is common to use as and then check for null. as only works on reference types, since value types cannot be null.
This is also explained in this longer article on MSDN.
By the way, the equivalent operator in VB is TryCast (versus DirectCast).
obj as T
is syntax sugar for
obj is T ? (T)obj : null
Thus, it is a "safe" cast. However, it takes longer, in theory. Thus, you should use normal casting unless you specifically want null if an object is not of the expected type. More often, you are better off handling it manually:
if (!(obj is T))
{
// Handle the case where obj is of an unexpected type.
}
T tobj = (T)obj;
Using the as keyword will set the variable web to null if the Parent is not of type SPWeb.
As where an explicit cast will throw an exception if the Parent is not of type SPWeb.
"as" is safer than (cast) as it will either return a value as the given type or null.
You will find that the following line will (or should) test for null.
If the cast fails the variable assigned to becomes null opposed to throwing an exception 'InvalidCastException '
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?
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 :)
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:
You don't know for sure what type myObject is
You want to do something with myObject, but only if it's of type MyType
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.
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.
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.
}
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.
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)
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
}
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".
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.
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.
If you use as, there won't be a runtime InvalidCastException, but table may be null, so you need to check for that.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Casting: (NewType) vs. Object as NewType
In C#, why ever cast reference types when you can use "as"?
Casting can generate exceptions whereas "as" will evaulate to null if the casting fails.
Wouldn't "as" be easier to use with reference types in all cases?
eg:
MyObject as DataGridView
rather than,
(DataGridView)MyObject
Consider the following alternatives:
Foo(someObj as SomeClass);
and:
Foo((SomeClass)someObj);
Due to someObj being of the wrong type, the first version passes null to Foo. Some time later, this results in a NullReferenceException being thrown. How much later? Depends on what Foo does. It might store the null in a field, and then minutes later it's accessed by some code that expects it to be non-null.
But with the second version, you find the problem immediately.
Why make it harder to fix bugs?
Update
The OP asked in a comment: isn't is easier to use as and then check for null in an if statement?
If the null is unexpected and is evidence of a bug in the caller, you could say:
SomeClass c = someObj as SomeClass;
if (c == null)
{
// hmm...
}
What do you do in that if-block? There are two general solutions. One is to throw an exception, so it is the caller's responsibility to deal with their mistake. In which case it is definitely simpler to write:
SomeClass c = (SomeClass)someObj;
It simply saves you writing the if/throw logic by hand.
There is another alternative though. If you have a "stock" implementation of SomeClass that you are happy to use where nothing better is available (maybe it has methods that do nothing, or return "empty" values, etc.) then you could do this:
SomeClass c = (someObj as SomeClass) ?? _stockImpl;
This will ensure that c is never null. But is that really better? What if the caller has a bug; don't you want to help find bugs? By swapping in a default object, you disguise the bug. That sounds like an attractive idea until you waste a week of your life trying to track down a bug.
(In a way this mimics the behaviour of Objective-C, in which any attempt to use a null reference will never throw; it just silently does nothing.)
operator 'as' work with reference types only.
Sometimes, you want the exception to be thrown. Sometimes, you want to try to convert and nulls are OK. As already stated, as will not work with value types.
One definite reason is that the object is, or could be (when writing a generic method, you may not know at coding-time) being cast to a value type, in which case as isn't allowed.
One more dubious reason is that you already know that the object is of the type in question. Just how dubious depends on how you already know that. In the following case:
if(obj is MyType)
DoMyTypeStuff((MyType)obj);
else
DoMoreGeneralStuff(obj);
It's hard to justify using as here, as the only thing it really does is add a redundant check (maybe it'll be optimised away, maybe it won't). At the other extreme, if you are half-way to a trance state with the amount of information you've got in you're brain's paged-in memory and on the basis of that you are pretty sure that the object must be of the type in question, maybe it's better to add in the check.
Another good reason is that the difference between being of the wrong type and being null gets hidden by as. If it's reasonable to be passing in a string to a given method, including a null string, but it's not reasonable to pass in an int, then val as string has just made the incorrect usage look like a completely different correct usage, and you've just made the bug harder to find and potentially more damaging.
Finally, maybe if you don't know the type of the object, the calling code should. If the calling code has called yours incorrectly, they should receive an exception. To either allow the InvalidCastException to pass back, or to catch it and throw an InvalidArgument exception or similar is a reasonable and clear means of doing so.
If, when you write the code to make the cast, you are sure that the cast should work, you should use (DataGridView)MyObject. This way, if the cast fails in the future, your assumption about the type of MyObject will cause an invalid cast exception at the point where you make the cast, instead of a null reference exception at some point later.
If you do want to handle the case where MyObject is not a DataGridView, then use as, and presumably check for it being null before doing anything with it.
tl;dr If your code assumes something, and that assumption is wrong at run-time, the code should throw an exception.
From MSDN (as (C# reference)):
the as operator only performs reference conversions and boxing conversions. The as operator cannot perform other conversions, such as user-defined conversions, which should instead be performed using cast expressions.
Taking into consideration all of the comments, we came across this just the other day and wondered why you would do a direct cast over using the keyword as. What if you want the cast to fail? This is sometimes the desirable effect you want from a cast if you're casting from a null object. You then push the exception up the call stack.
So, if you want something to fail, use a direct cast, if you're okay with it not failing, use the as keyword.
As is faster and doesn't throw exceptions. Therefore it is generally preferred. Reasons to use casts include:
Using as, you can only assign types that are lower in the inheritance tree to ones that are higher. For example:
object o = "abc" as object;
DataGridView d = "abc" as DataGridView // doesn't do anything
DataGridView could create a custom cast that does allow this. Casts are defined on the target type and therefore allow everything, as long as it's defined.
Another problem with as is that it doesn't always work. Consider this method:
IEnumerable<T> GetList<T>(T item)
{
(from ... select) as IEnumerable<T>
}
This code fails because T could also be a Value Type. You can't use as on those because they can never be null. This means you'll have to put a constraint on T, while it is actually unnecesary. If you don't know whether you're going to have a reference type or not, you can never use as.
Of course, you should always check for null when you use the as keyword. Don't assume no exceptions will be thrown just becase the keyword doesn't throw any. Don't put a Try {} Catch(NullReferenceException){} around it, that't unneccesary and bloat. Just assign the value to a variable and check for null before you use it. Never use it inline in a method call.
This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Casting: (NewType) vs. Object as NewType
Say for example I have a class called MyObjectType and I want to convert the sender parameter of an event to this type. I would usually go about it by simply doing this:
MyObjectType senderAsMyType = (MyObjectType) sender;
I've recently realised that it can also be done like this:
MyObjectType senderAsMyType = sender as MyObjectType;
Which way is most efficient? So that I can make my code consistent and use one of the ways throughout. Or do they both have pro's and cons? If so please could someone inform me of them.
Thanks again,
If you wish to avoid any InvalidCastExceptions use
MyObjectType senderAsMyType = sender as MyObjectType;
otherwise use
MyObjectType senderAsMyType = (MyObjectType)sender;
if an InvalidCastException represents a true exceptional situation in your application.
As for performance, I would contend that you would find no discernible difference between the two different kinds of casting. I was interested though so I used Jon Skeet's BenchmarkHelper and achieved results that confirmed my suspicions:
Test:
using System;
using BenchmarkHelper;
class Program
{
static void Main()
{
Object input = "test";
String output = "test";
var results = TestSuite.Create("Casting", input, output)
.Add(cast)
.Add(asCast)
.RunTests()
.ScaleByBest(ScalingMode.VaryDuration);
results.Display(ResultColumns.NameAndDuration | ResultColumns.Score,
results.FindBest());
}
static String cast(Object o)
{
return (String)o;
}
static String asCast(Object o)
{
return o as String;
}
}
Output:
============ Casting ============
cast 30.021 1.00
asCast 30.153 1.00
I think this answer will help...
Casting: (NewType) vs. Object as NewType
Basic difference: if sender is not an instance of MyObjectType or one of its subclasses, the first example (direct cast) throws an exception; the second (as operator) returns null.
None of them is plainly better or worse; you should use the one or the other according to the situation you are facing at the moment. If sender is not a MyObjectType what do you want to do? probably, in this case, since it's an event handler, throwing exception is perfectly fine...
You should use (MyObjectType) whenever possible, because you will get an exception right away if the cast fails. With as you might get a NullRef-exception anywhere later.
Use as only when you handle a failed cast right afterwards.
They do slightly different things. It depends on what you want.
// Will throw an exception if the cast cannot be made
MyObjectType foo = (MyObjectType)bar;
or
// Will return null if the cast cannot be made
MyObjectType foo = bar as MyObjectType;
Which you use is up to you? If you expect the cast to potentially fail frequently (and you are happy with that) go for as and test for null afterwards, if you expect it never to fail go for (type).
Remember, that if the reference can be null anyway and you need to know that too, test for null before the cast.
MyObjectType senderAsMyType = (MyObjectType) sender;
This will throw an InvalidCastException if sender cannot be cast to MyObjectType.
MyObjectType senderAsMyType = sender as MyObjectType;
senderAsMyType will be null if sender cannot be cast to MyObject. This method cannot be used with value types.
I believe the latter is marginally faster, but the difference is virtually insignificant.
It depends on your expectations of your objects. If the object should be of that type, and you need to access that objects members, use:
MyObjectType senderAsMyType = (MyObjectType) sender;
As stated before, this throws an InvalidCastException for you if it is invalid
If it might be of that type, and you only want to take action if it is, use 'as', and check for null
MyObjectType senderAsMyType = sender as MyObjectType;
if(senderAsMyType != null)
{
senderAsMyType.MyMethod()
}
However if you are only checking the type, but do not need the object, use the 'is' operator, as this will be cheapest resource-wise
if(sender is MyObjectType)
//do something
Don't worry too much about efficiency, it's better to make the decision based on semantics. Whether one is more efficient than the other will depend heavily on individual circumstance, and how many times you expect it to fail.
A straight cast "(ObjectType)" can fail, and will throw an InvalidCastException.
"as" will not fail with an exception, but instead will return a null object if the cast doesn't work.
If the cast is definitely valid, just do the cast. That way if things go wrong you will get the exception and hopefully be able to solve the problem.
If you aren't certain of the object type, it can be useful to use "as" and just check for null
From the best practises perspective you should use the as keyword if you expect objects of different types and your code can handle them, e.g.
public void MyFunction(MyObject obj)
{
obj.DoSomething();
SpecializedObject specialized = obj as SpecializedObject;
if(specialized!=null)
{
specialized.DoSthSpecial();
}
}
And use the normal cast when you are sure the type will be what you expect, you just need to cast it because of technical reasons:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
MyObject obj = (MyObject)xmlSerializer.Deserialize(xml);
this way its not only faster, but also doesn't hide errors.
If there is a difference, what is the difference between the two ways of doing the following cast?
In this case e is a GridViewRowEventArgs object.
GridView gv = (GridView)e.Row.FindControl("gv"); //first way
GridView gv2 = e.Row.FindControl("gv") as GridView; //second way
The differences are:
If a cast fails, it throws an InvalidCastException.
If the as operator fails, it just returns a null reference.
You can't use as with non-nullable value types (e.g. you can't do "o as int").
The cast operator is also used for unboxing. (as can be used to unbox to a nullable value type.)
The cast operator can also perform user-defined conversions.
EDIT: I've written elsewhere about when I feel it's appropriate to use which operator. That might be worth a read...
What isn't mentioned in the above answers is intent -- why are you performing the conversion, and (more importantly) what happens on the lines after the conversion?
For example, I've seen code similar to the following a number of times:
if ((foo as SomeType).SomeMethod()) { /* ... */ }
This could be compared to the cast-using version:
if (((SomeType) foo).SomeMethod()) { /* ... */ }
So, which of these is better?
The cast is.
Using as will result in a NullReferenceException if the conversion fails.
Using a cast will result in an InvalidCastException if the conversion fails.
Now tell me, which is a more useful exception for debugging? A NullReferenceException, which could be produced by nearly anything, or an InvalidCastException, which lets you know what actually went wrong?
Thus, only use as if the conversion is actually optional (meaning that there must be a null check before using the variable). Otherwise, use a cast, thus making your intentions more explicit.
The safe cast as
variable as type
does the same as
(variable is type) ? (type)variable : (type)null
and will not work for value types.
In general, the difference between a static cast and "as", is that the cast will throw an Exception if it fails, whereas "as" will just set the variable to null.
The "as" statement basically makes an attempt to cast the variable, and returns null if it fails rather than throwing an exception. As such, the value to which you're casting must be nullable - a reference type or a nullable primitive. In your example, you'd have to do:
int? i2 = o as int;
or it won't compile.
If you however used a reference type say Table the first one would raise InvalidCastException in case o was not assignable to Table and the second would just return null.
Apart from the issue which Jon pointed out, the as keyword effectively casts o as SomeClass. If o isn't derived from SomeClass it returns null. Whereas a simple cast would throw an exception.
SomeClass i2 = o as SomeClass;
becomes
SomeClass i2;
if (o is SomeClass)
i2 = (SomeClass)o;
else
i2 = null;
I might be stating the obvious here, but one thing that you get with the 'as' cast is, that you are guaranteed to end up with an object of the type you requested.
This comes in handy in certain situations.