What is the difference between an explicit cast and the as operator?

19

Always when I convert an object to a specific type, I use an explicit cast , for example:

private void textBox1_Leave(object sender, EventArgs e)
{
    TextBox textBoxTemp = (TextBox)sender;
    MessageBox.Show("Você digitou: " + textBoxTemp.Text);
}

I can do the same thing using the as operator like this:

private void textBox1_Leave(object sender, EventArgs e)
{
    TextBox textBoxTemp = sender as TextBox;
    MessageBox.Show("Você digitou: " + textBoxTemp.Text);
}

I would like to know the difference between the two approaches, when to use one or the other, and whether there is any difference in performance between them.

    
asked by anonymous 22.01.2015 / 19:21

5 answers

18

Explicit cast throws exception if object is not of type.

private void textBox1_Leave(object sender, EventArgs e)
{
    TextBox textBoxTemp = (TextBox)sender;  // lança exceção se não for TextBox... InvalidCastException (eu acho que esse é o nome)
    MessageBox.Show("Você digitou: " + textBoxTemp.Text);
}

It is used when you are almost certain that the type is correct ... not being allowed to use the method in question textBox1_Leave for any other type of object passed in sender .

The as operator does not throw an exception, and returns null if the object is not of type.

private void textBox1_Leave(object sender, EventArgs e)
{
    TextBox textBoxTemp = sender as TextBox; // não lança exceção
    MessageBox.Show("Você digitou: " + textBoxTemp.Text); // se não for do tipo, então vai lançar exceção aqui, NullPointerException
}

The correct way to use the as operator is to test whether the return is null or not, so as not to run the risk of throwing a generic exception, such as would occur (exemplified above).

Correct:

    TextBox textBoxTemp = sender as TextBox;
    if (textBoxTemp != null)
        MessageBox.Show("Você digitou: " + textBoxTemp.Text);
    else
        // fazer algo quando for nulo

Cast overload

It is possible to overload the explicit cast operator only. as can not have its behavior changed.

This means that from time to time the explicit cast is doing more things than it looks:

class MyClass
{
    public static explicit operator int(MyClass x)
    {
        return x.GetValor(); // fazendo uma operação qualquer no cast
    }
}

And somewhere else, casting from MyClass to int , will actually be called the above method:

var x = (int)myClass; // cast sobrecarregado

Operator as

The as operator can only be used to convert to a nullable type. You can not use a non-nullable type on the right operand. That is, any class or Nullable<T> .

valid: 1 as int? ; obj as UmaClasse

Invalid:

object num = 1;
int num2 = num as int; // inválido
    
22.01.2015 / 19:29
6

In addition to the explanation already given that cast ( (TextBox)sender ) throws exception while ( sender as TextBox ) returns null if the types are not compatible, :

Using one or the other is not just about avoiding an exception, but about revealing intent

TextBox textBoxTemp = (TextBox)sender;

The above code says that it does not allow sender not to be TextBox . If it is not, that it blows up, that an exception is thrown and that it is caught by anyone who is interested, or that it breaks the application, because the code around only interests me if sender is actually TextBox .

Already this code:

TextBox textBoxTemp = sender as TextBox;

You are telling me that it is perfectly acceptable that sender is not a TextBox , and that I have a plan for both situations. In this case, as already explained, it makes sense that there is a test textBoxTemp != null before quitting using this variable.

While the cast can actually cause a cast, "as" only does boxing / unboxing

If there was a deployed user conversion on the object sender , using as would not activate this conversion. as can only return a type whose compatibility has been defined by the object hierarchy, either by inheritance or by interface implementation.

It would not be wrong to say, for the sake of simplicity, that while the cast operator, example: (TextBox)sender , can be used for explicit type conversion, strong>, example sender as TextBox , can be used to obtain a polymorphic representation of the object, with no actual conversion.

    
22.01.2015 / 19:50
5

Cast classic

private void textBox1_Leave(object sender, EventArgs e) {
    TextBox textBoxTemp = (TextBox)sender;
    MessageBox.Show("Você digitou: " + textBoxTemp.Text);
}

Are you absolutely sure that sender is of type TextBox ? As I know the pattern of Windows Forms you are using I would say yes, it is. Therefore this "conversion" will not fail, it is certain that it is possible. Whatever situation you know will not fail you can use it. In many cases the cost is zero.

But I will reinforce that you have to be sure, it is not always possible to guarantee this.

Please note that if there is an error in the conversion attempt the application will throw an exception and possibly break. And this is good. It was a programming error somewhere. You should fix the bug. You should not catch the exception and try to fix it . Programming errors should be solved by the programmer, not the code. One possible solution is to not use the cast operator like this.

Operator as

This is where the as operator enters. The use of it implies that you are not very sure that the operation will work. Then we can consider that it works as an attempt and if it fails the object it should receive the "conversion" will receive the null value. That is why always after using as you must check if the object is not null. So you would:

private void textBox1_Leave(object sender, EventArgs e) {
    TextBox textBoxTemp = sender as TextBox;
    if (textBoxTemp != null) {
        MessageBox.Show("Você digitou: " + textBoxTemp.Text);
    }
}

Operator null-propagating

In C # 6 you can opt for this code:

private void textBox1_Leave(object sender, EventArgs e) {
    TextBox textBoxTemp = sender as TextBox;
    MessageBox.Show("Você digitou: " + textBoxTemp?.Text);
}

Not that the result is the same, but if you just do not want it to go wrong, it might be a good choice. It does not seem to be the case in this example since it will display the message "You typed:" and nothing else, it will not indicate problem, nothing.

Cost of operator as plus verification that the operation was successful is often the same as using cast in most situations. And when there is difference, it is not absurd. Anyway you should use whatever is right for the situation.

as can not directly convert type-valued types since they can not have null results. However you can use a nullable type to get the same result.

It also can not do user-defined conversions (even those defined within .Net), only language-defined conversions are possible. These conversions usually require some processing and can only be done with traditional cast .

Common error

Do not make exaggerations how to do this:

if (sender is TextBox) {
    TextBox sender = (TextBox) textBoxTemp;
    //faz algo aqui
}

It is common to see this in some code to "avoid" throwing the exception. This is wrong. This code is comparing if the type is compatible once in if and then compares again within cast .

Worse, in some cases there may be a race since you enter the first check and the actual conversion status of the object may have changed.

Conclusion

Note that operators have different semantics, they are used for different situations. When using one or the other should make you think of the design of the application, you should understand why you are using one or the other. It's not just a choice of what works or not.

Partially inspired response in this SO response .

    
22.01.2015 / 20:07
3

One throws Exception, and the other only returns null if they fail.

private void textBox1_Leave(object sender, EventArgs e)
{
    TextBox textBoxTemp = (TextBox)sender; // se por algum acaso, o objeto sender, não for do tipo TextBox, você terá um InvalidCastException
    MessageBox.Show("Você digitou: " + textBoxTemp.Text);
}

private void textBox1_Leave(object sender, EventArgs e)
{
    TextBox textBoxTemp = sender as TextBox; // já aqui, se por algum acaso, o objeto sender, não for do tipo TextBox, ele só retorna um objeto null.
    MessageBox.Show("Você digitou: " + textBoxTemp.Text); // então aqui sim lançaria uma NullPointerException
}

The form of treatment to avoid Exception is much more efficient and simple with as , with Cast , as shown below:

private void textBox1_Leave(object sender, EventArgs e)
{
    // com try catch, é não é eficiente para tratar dados
    try
    {
        TextBox textBoxTemp = (TextBox)sender; // se por algum acaso, o objeto sender, não for do tipo TextBox, você terá um InvalidCastException
        MessageBox.Show("Você digitou: " + textBoxTemp.Text);
    }
    catch (InvalidCastException ex)
    {
        //Ou simplismente sem nada, "padrão Silenciator" (um grande designer pattern, hehe)
        MessageBox.Show(ex.Message);
    }
}

private void textBox1_Leave(object sender, EventArgs e)
{
    TextBox textBoxTemp = sender as TextBox; // já aqui, se por algum acaso, o objeto sender, não for do tipo TextBox, ele só retorna um objeto null.
    // com uma simples verificação de referencia diferente de null
    if (textBoxTemp != null)
    {
        MessageBox.Show("Você digitou: " + textBoxTemp.Text);
    }
}

You can also use the is statement, which does a typing check, to then convert to the correct type. And it's also very useful if you're expecting a few different types like:

if (sender is TextBox)
{
    TextBox textBoxTemp = sender as TextBox;
} else if (sender is Button)
{
    Button buttonTemp = sender as Button;
}
// e pode ter outras verificações

With is is the way I usually use it. For making me look nicer.

    
22.01.2015 / 19:32
0

cast throws Exception if the object is not of type and as only returns null .

    
30.11.2016 / 17:27