65

From the docs:

The as operator is like a cast except that it yields null on conversion failure instead of raising an exception. More formally, an expression of the form:

   expression as type

is equivalent to:

  expression is type ? (type)expression : (type) null

except that expression is evaluated only once.

So why wouldn't you choose to either do it one way or the other. Why have two systems of casting?

Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
patrick
  • 16,091
  • 29
  • 100
  • 164

7 Answers7

95

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/

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
15

Efficiency and Performance

Part of performing a cast is some integrated type-checking; so prefixing the actual cast with an explicit type-check is redundant (the type-check occurs twice). Using the as keyword ensures only one type-check will be performed. You might think "but it has to do a null check instead of a second type-check", but null-checking is very efficient and performant compared to type-checking.

if (x is SomeType )
{
  SomeType y = (SomeType )x;
  // Do something
}

makes 2x checks, whereas

SomeType y = x as SomeType;
if (y != null)
{
  // Do something
}

makes 1x -- the null check is very cheap compared to a type-check.

John Mills
  • 10,020
  • 12
  • 74
  • 121
STW
  • 44,917
  • 17
  • 105
  • 161
  • 4
    Why is there a typeof in there? That doesn't make any sense. – Eric Lippert Jul 01 '10 at 17:25
  • @Eric -- roger! my bad, it's out – STW Jul 01 '10 at 17:27
  • 1
    @Dykam the actual type comparison of (x is SomeType) performs 1x type-check, and the second is performed as part of the casting process (it needs to find out if the types are compatible so that it can throw an excepiton if necessary) – STW Jul 01 '10 at 17:28
  • That would explain why it's a CLR feature, but not why it's a language feature. The former case would be very easy for a compiler to recognize and convert to a single check internally. – Ken Jul 01 '10 at 17:30
  • @Ken not sure if the compiler could/should do this as part of it's optimizations--but it's a pattern that FxCop will flag – STW Jul 01 '10 at 17:33
14

Because sometimes you want things to fail if you can't cast like you expect, and other times you don't care and just want to discard a given object if it can't cast.

It's basically a faster version of a regular cast wrapped in a try block; but As is far more readable and also saves typing.

Amber
  • 507,862
  • 82
  • 626
  • 550
  • That explains why this feature exists for casting, but not why it wouldn't also apply to a dozen other things. I often also want other things in the language to silently return null, like dictionary lookups or enum parsing. Why is casting so special? – Ken Jul 01 '10 at 17:28
  • 3
    Dictionaries and Enums have their safe-returning methods, they're called TryGetValue and TryParse respectively... – digEmAll Jul 01 '10 at 17:33
  • Amber, just curious if you have a reference to how `as` implements its try/catch--your answer and TomTom's are somewhat conflicted over this detail. – STW Jul 01 '10 at 17:34
  • 1
    STW: "basically a faster version" wasn't intended to mean literally a try block, just an equivalent to what could be done with one. – Amber Jul 01 '10 at 17:38
  • Daniel: Yes, it does now, in 4.0. It took over 8 years for them to add that. – Ken Jul 01 '10 at 19:14
  • digEmAll: Sure, but those are methods, not special syntax with their own reserved words. Why does casting get special syntax? (You could theoretically write an extension method `As(object)` that used casting internally, right?) – Ken Jul 01 '10 at 19:17
7

It allows fast checks without try/cast overhead, which may be needed in some cases to handle message based inheritance trees.

I use it quite a lot (get in a message, react to specific subtypes). Try/cast wouuld be significantly slower (many try/catch frames on every message going through) - and we talk of handling 200.000 messages per second here.

TomTom
  • 61,059
  • 10
  • 88
  • 148
  • 3
    Just curious whether you or Amber is correct regarding the try/catch--sounds like `as` does wrap the operation in a Try-block, but perhaps uses a more efficient casting mechanism? – STW Jul 01 '10 at 17:35
  • 1
    @STW: I was thinking the same thing... If you have your own try/catch or `as` has its own try/catch, the performance should be comparable. – Nelson Rothermel Jul 01 '10 at 17:39
  • Talking about try/cast overhead, take a look here [(with an apology from C# team)](http://stackoverflow.com/a/8947323/227755) – nurettin Dec 25 '12 at 07:57
3

Let me give you real world scenarios of where you would use both.

public class Foo
{
  private int m_Member;

  public override bool Equals(object obj)
  {
    // We use 'as' because we are not certain of the type.
    var that = obj as Foo;
    if (that != null)
    {
      return this.m_Member == that.m_Member;
    }
    return false;   
  }
}

And...

public class Program
{
  public static void Main()
  {
    var form = new Form();
    form.Load += Form_Load;
    Application.Run(form);
  }

  private static void Form_Load(object sender, EventArgs args)
  {
    // We use an explicit cast here because we are certain of the type
    // and we want an exception to be thrown if someone attempts to use
    // this method in context where sender is not a Form.
    var form = (Form)sender;

  }
}
Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
2

I generally choose one or the other based on the semantics of the code.

For example, if you have an object that you know that it must be an string then use (string) because this expresses that the person writing the code is sure that the object is a string and if it's not than we already have bigger problems than the runtime cast exception that will be thrown.

Use as if you are not sure that the object is of a specific type but want to have logic for when it is. You could use the is operator followed by a cast, but the as operator is more efficient.

João Angelo
  • 56,552
  • 12
  • 145
  • 147
0

Maybe examples will help:

// Regular casting
Class1 x = new Class1();
Class2 y = (Class2)x; // Throws exception if x doesn't implement or derive from Class2

// Casting with as
Class2 y = x as Class2; // Sets y to null if it can't be casted.  Does not work with int to short, for example.

if (y != null)
{
  // We can use y
}

// Casting but checking before.
// Only works when boxing/unboxing or casting to base classes/interfaces
if (x is Class2)
{
  y = (Class2)x; // Won't fail since we already checked it
  // Use y
}

// Casting with try/catch
// Works with int to short, for example.  Same as "as"
try
{
  y = (Class2)x;
  // Use y
}
catch (InvalidCastException ex)
{
  // Failed cast
}
Nelson Rothermel
  • 9,436
  • 8
  • 62
  • 81