I am a relative newbie to C# as most of my web development work has been in VB.
In VB something like a DataRow Object or Session Object will implicitly cast to say a string. I can say:
If myDataRow("name") = "Fred" Then ...
I appreciate that in C# this casting must be explicit, so my question - all three of the lines below compile and work as expected. The ToString() will throw an exception if the session object is null so I guess that option is less 'good' as I would have to check for null first, but is one option more efficient or considered better C# coding practice than the others? Thanks a lot.
if ((string)Session["test"] == "abc") ...
if (Session["test"] as string == "abc") ...
if (Session["test"].ToString() == "abc") ...
There are many good responses to this here: Direct casting vs 'as' operator?
In short, the first option i.e. (string)Session["test"] == "abc" will throw a InvalidCastException if Session["test"] is not a string. Use this if you might want to throw an error on invalid cast.
The second option Session["test"] as string == "abc" will return null if the object which is typecasted is not a string. This option requires an explicit null check to be done post conversion before actually using the result.
If you definitely know that the object which you are typecasting is a string, you can use the first one and if in case it fails, you will definitely know that the cast failed and is easier to debug. If you are not sure of whether the object is a string, you might want to go for the second option.
As already pointed out in the comments above, there's a fourth possibility, which works with recent compiler versions:
if (Session["test"] is string test && test == "abc")
{
// will get here only if the field was not null and is "abc"
}
The is operator returns false if the object is null, but if it is not null and the type matches, the value is assigned to the variable.
Related
This question already has answers here:
Casting vs using the 'as' keyword in the CLR
(18 answers)
Closed 9 years ago.
How does the "is" operator work in C#?
I have been told that this :
if (x is string)
{
string y = x as string;
//Do something
}
is not as good as this:
string y = x as string;
if (y != null)
{
//Do something
}
Which is better and why?
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.
I think second is better cause in first case it will cast object 2 times, first time with is operator and second time in as operator.
while in second case it cast only one time.
The is operator checks if an object can be cast to a specific type or not
like
if (someObj is StringBuilder)
{
StringBuilder ss = someObj as StringBuilder
....
}
The as operator cast an object to a specific type, and returns null if it fails.
like
StringBuilder b = someObj as StringBuilder;
if (b != null) ...
I would use the first approach when more than one type is expected to be stored in x. (You might be passed a string, or a StringBuilder etc). This would allow for non-exception based handling.
If you are always expecting x to hold a certain type of value, then I would use the second option. The check for null is inexpensive and provides a level of validation.
-- Edit --
Wow. After reading some of the comments below, I started looking for more updated information. There is a LOT more to consider, when using as vs is vs (casting). Here are two interesting reads I found.
Does it make sense to use "as" instead of a cast even if there is no null check? and http://blogs.msdn.com/b/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx?PageIndex=1#comments
Both of which seem to be well summarized by Jon Skeet's blog. http://www.yoda.arachsys.com/csharp/faq/#cast.as
According to the Constraints on Type Parameters (C# Programming Guide) documentation it says, and I quote:
When applying the where T : class constraint, avoid the == and !=
operators on the type parameter because these operators will test for
reference identity only, not for value equality. This is the case even
if these operators are overloaded in a type that is used as an
argument. The following code illustrates this point; the output is
false even though the String class overloads the == operator.
With the following example:
public static void OpTest<T>(T s, T t) where T : class
{
System.Console.WriteLine(s == t);
}
static void Main()
{
string s1 = "target";
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
string s2 = sb.ToString();
OpTest<string>(s1, s2);
}
However, ReSharper (I've just started using the demo/trial version to see if it is any worth to me) gives a hint/tip to do null-checking of parameters like so:
public Node(T type, Index2D index2D, int f, Node<T> parent)
{
if (type == null) throw new ArgumentNullException("type");
if (index2D == null) throw new ArgumentNullException("index2D");
if (parent == null) throw new ArgumentNullException("parent");
}
(T is constrained with where T : class, new())
Can I safely follow ReSharper without running into problems that the C# documentation is trying to tell me to avoid?
Yes, that is fine. The documentation says not to compare two parameters because you're doing a reference comparison. The code ReSharper suggests is just ensuring the reference you've been passed is not null so that is safe to do.
In my opinion the main reason the C# docs recommend you don't do that is because if for example you do == with two strings that were passed as T1 and T2 it will do a reference comparison. Any other time you do stringA == stringB it will do a value comparison with the overload in the string class. It's really just warning against doing these types of comparisons because the operator overload that would normally be used (if you used that operator on two types declared in local scope) is not.
Yes.
Only a very strange implementation of the == operator would make x == null mean something other than ReferenceEquals(x, null). If you are using classes that have such a strange implementation of equality, you have bigger problems than it being inconsistent when checking for null using a generic type argument.
The documentation is telling you that == will use a reference comparison regardless of what the actual type of T is, even if it has overloaded the == operator. In many cases this isn't what users would expect.
In the case of the resharper code it's comparing the variable to null, which you want to be a reference comparison, not a value comparison, so what the documentation is warning you of is the correct behavior here.
You could however make it a bit more explicit by writing something like this, just to be clearer:
if(object.ReferenceEquals(type, null))//...
Yes, it's generally ok to assume that null is a special case, and that it's okay to do == or != on it. This is due, in part at least, to the fact that the recommendation for overriding Equals says that x.Equals(null) should be false.
If you didn't have the T : class constraint, it'd be a different story, since you'd see some possibly-unexpected behavior for structs and nullable structs (you might want to do default(T) instead of null there).
And if you want to be explicit that yes, you know you're comparing the reference to null, you can always use object.ReferenceEquals(x, null) (I'd just go with ==/!=, though).
I would say that this is OK.
null is kinda special, so you are not doing an actual comparison between two reference variables, you are just assuring that the reference variable is not a null reference.
Compare this with, for example, SQL. There you have a completely different syntax for comparing ( a = b) and for the null check (a is null). The guideline is that you should avoid the first, but the second is ok.
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.
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.