Are there compelling reasons AGAINST using the C# keyword "as"? - c#

I find that using the following:
TreeViewItem i = sender as TreeViewItem;
if(i != null){ ... }
is easier to write and understand than:
if(sender.GetType() == typeof(TreeViewItem)){
TreeViewItem i = (TreeViewItem)sender;
...
}
Are there compelling reasons not to use the first construct?

I prefer casts to as in most cases because usually if the type of the object is wrong, that indicates a bug. Bugs should cause exceptions IMO - and an InvalidCastException at exactly the line which performs the cast is a lot clearer than a NullReferenceExceptionmuch later in the code.
as should be used when it's valid and legal to have been passed a reference to an object of the type that you don't want. That situation does come up, but not as often as normal casting in my experience.
Comparing types using GetType(), however, is very rarely the right solution - it's only appropriate when you want to check for the exact type involved rather than a compatible type.
I've written a significantly longer answer about the "cast vs as" discussion elsewhere.

Not at all - it gives you the chance to verify that the conversion (cast) was done OK. If you do
TreeViewItem i = (TreeViewItem) sender;
you might get an exception if the cast fails.

Generally speaking, these two snippets are not equivalent. TreeViewItem i = sender as TreeViewItem will yield a correct result even if sender is a grand-grand-child of TreeViewItem, whereas sender.GetType() == typeof(TreeViewItem) will be true only when sender is precisely TreeViewItem and none of its possible subclasses.

"as": good stuff. use it all the time.
if you really want an alternative to manually comparing types try:
if(person is Employee) { }
reads better yet.

Your example would be better written as:
if (sender is TreeViewItem) {
TreeViewItem i = (TreeViewItem)sender;
...
}
It is exactly this dual type checking that the as operator can help avoid. So for your cited example, I would say it is definitely a good solution.
However, there are situations where you really do want a cast. If you're expecting a TreeViewItem and want nothing else, casting will ensure an InvalidCastException is thrown if you're given anything else.
Just like in most situations, there is no blanket rule here: use the right tool for the right job.

If you want a plain (not nullable) value type, obviously this won't work, eg:
int test = sender as int;
isn't valid, however:
int? test = sender as int?;
is allowed.

No, I use it quite a bit. It allows you to avoid InvalidCastExceptions in a clean way.
For example:
TreeViewItem tvItem = sender as TreeViewItem;
if (tvItem != null) return;
// Do stuff
as opposed to:
try
{
TreeViewItem tvItem = (TreeViewItem)sender;
// Do stuff.
}
catch (InvalidCastException ex)
{
// Didn't work, do something about it
return; // ... or not...
}

"as" is faster, but things to bear in mind are:
"as" returns a null instead of throwing an exception if that's a problem
it won't do custom conversions iirc
it doesn't work for reference->value
Edit: "as" definitely is faster (http://www.codeproject.com/KB/cs/csharpcasts.aspx)
Edit2: so basically a speed vs safety decision

If getting the wrong type would be a bug, then you should use a cast. The reason for this is that there really is a problem and you should know about it.
If it is possible that the value will be null, and that is not a bug in the system when this happens then use "as". The reason being that you should use "as" any time that getting a null back is acceptable.
Keep in mind that you can't use "as" to convert to value types, because the null value is not acceptable for them. If you have a value type and want to use "as", you will need to use a nullable value type.
When to Use "as" Versus Casting

Related

How to automatically cast variables in C#?

Here is a example.
var tobeCasted = 1;
object data = null;
if (whatIsMyType == typeof(int)) {
data = (int)tobeCasted;
}
else if (whatIsMyType == typeof(float)) {
data = (float)tobeCasted;
}
However the above code is manually detected each data type.
I'm looking for a one line general solution like following :
data = (whatIsMyType)tobeCasted;
Use the Convert.ChangeType method. The documentation for the Convert class is here; it contains many useful methods for runtime type coercion.
http://msdn.microsoft.com/library/system.convert.aspx
That said, try to avoid this if you can. This kind of runtime typing can be considered a bad code smell.
In this particular case, I think you want Convert.ChangeType:
object data = Convert.ChangeType(toBeCasted, whatIsMyType);
Of course that only works with a limited set of types - but then so does casting in the first place. If you can tell us more about what you're trying to do, it would be helpful. There may very well be a better approach.
If you're sticking the result into a variable of type Object, just do that. As you have it now, you're casting to int/float/whatever, then casting to Object. Cut out the middle man.
var tobeCasted = 1;
object data = tobeCasted;
Your example is too trivial to understand your real need, but Maybe something like TypeMapper is more suited for your use.

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?
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.

Why ever cast reference types when you can use "as"? [duplicate]

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.

Is there a reason to do a type comparison this way?

I'm used to seeing old code like
if (true)
{
...
}
where it's intuitively clear that someone was being either lazy or overly cautious when making a change. I ran across this snippet today, and I'm curious whether there's a functional difference between doing type comparison this way:
private static bool logField(Type t, string fieldname)
{
if (t.ToString() == typeof (Property).ToString())
{
...
}
return true;
}
and doing it this way:
private static bool logField(Type t, string fieldname)
{
if (t == typeof (Property))
{
...
}
return true;
}
I'd say that's generally laziness - but it may not be. For example, you could have two Property types, in the same effective file, but different copies. If typeof(Property) loads it from one file but t is loaded from a different one, your replacement would say they were different but the original code would compare say they were the same.
It's definitely an edge case, and one that you normally want to avoid in the first place... but it's just possible.
I can't think of any good reasons.
In fact, the former will throw if t is null.
The first one compares references of Strings, while the second one actually checks to see if t is of the Property type.
The first one will always be "correct" because the two strings refer to the same object, but the second one is the correct way to check if t is of the Property type.
An equivalent and more readable way to do a type check is
if (t is Property)
No, getting the type object of 2 instances of the same type will always return a reference to the same type object in memory. This means that performing a reference equality check (==) is sufficient.
Essentially, calling:
if (t.ToString() == typeof (Property).ToString())
will call ToString() twice on the same object, where t is the 'Property' type.
I'd say that the first approach was probably done by someone unfamiliar with C#, not necessary being lazy. The string comparison will work for a majority of the time, except:
If t is null it would throw a null reference exception.
It doesn't take namespaces into consideration.
I would recommend the second case, unless you fall into needing the #2 edge case.

Should I use (ObjectType) or 'as ObjectType' when casting in c#? [duplicate]

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.

Categories

Resources