7

Consider the following code:

DerivedClass drbObj = (DerivedClass)obj;

Here obj is of type Object and this is reasonable since Object is the base type of every Class in C#.

Here, since the type of derObj is defined at compile time, what is the need to explicitly use type conversion here. Can't the compiler predict on it's own that it will be of DerivedClass. I understand that, the Conversion type doesn't have to match the Derived type, but for practical purpose, it will only be as useful as the Derived type.

Could someone explain with a small, hypothetical example, as to why the Explicit Type Conversion is necessary when a reference of type Object is being assigned to a derived class.

From what I know, in C, there is no need to do perform Explicit type conversion from void* to any pointer and the compiler can handle it, based on the type of the pointer to which the converted value is being assigned.

4
  • 1
    Trying DerivedClass drbObj = (DerivedClass)obj; where class DerivedClass : Object was an InvalidCastException however DerivedClass drgObj = obj as DerivedClass; worked just fine. That may just be nit-picking though :)
    – Dylan Yaga
    Commented Oct 27, 2011 at 11:52
  • 2
    @DylanYaga, using (SomeType)x and x as SomeType are two very different constructs in C# (don't know about other languages). The first is an assertion (you're willing to deal with the exception if the types are incompatible), the second is an attempt (and yields null if the types are incompatible).
    – user
    Commented Oct 27, 2011 at 12:24
  • @MichaelKjörling Always learning, thank you :) This may also help Direct casting vs 'as' operator?
    – Dylan Yaga
    Commented Oct 27, 2011 at 12:45
  • C is 30-something years older than C#. C has "weak typing" and allows/performs a lot of implicit conversions. This is one of the major flaws of the C language.
    – user29079
    Commented Oct 27, 2011 at 13:50

4 Answers 4

9

The reason why you have to do this is pretty simple:

Because that's the way the language was designed.

While yes, the C# designers could have decided to infer that your intent was to cast obj based solely on your declaration, they chose not to do so, probably because such an inference would cause more problems than it solved.

I can think of two reasons why they might have chosen not to infer the cast to DerivedObj:

1) Because it's inconsistent. Though for assignment (as in your example) it may seem logical to perform the inference, there are a ton of situations you would need to perform the cast explicitly, and making the casting behavior consistent makes the language conceptually simpler. For example, let's say you were writing a piece of code that needed to set the obj's ID to 5, knowing ahead of time that it was a DerivedObj. You'd still have to do the cast:

((DerivedObj)obj).ID = 5;

2) Because it's dangerous. Performing the cast at assignment is an "are you sure?" kind of check which makes you think twice about what the object really is before assigning. I would say that's a feature of the language, and definitely not worth a special-case casting behavior just for assignment. In fact, if you really created obj by saying obj = new object() somewhere, the cast will fail anyway.

3

Can't the compiler predict on it's own that it will be of DerivedClass.

No? How on earth would it predict that? You want it to solve the Halting problem? Objects may be useless (and a shitty, shitty design) but there are millions of classes derived from Object. How would the compiler know which one to pick?

The reason the cast is necessary is because it could fail at run-time, and the compiler wants to know that you're sure. Explicit casting is much safer than implicit casting.

From what I know, in C, there is no need to do perform Explicit type conversion from void* to any pointer and the compiler can handle it, based on the type of the pointer to which the converted value is being assigned.

That's a bad thing, not a good thing, and conversion != casting. Casts are bad. Try not to use them.

7
  • 9
    "Casts are bad??" That's the first time I've ever heard someone say that. Commented Oct 27, 2011 at 11:48
  • 1
    @DaveMarkle: Then you obviously don't listen to the right people. Casts should be used with the same caution as gotos.
    – back2dos
    Commented Oct 27, 2011 at 12:16
  • 2
    The type system is safe. Casting subverts that safety.
    – DeadMG
    Commented Oct 27, 2011 at 12:48
  • 1
    "Cannot convert const int* to int* ? Bah, eat typecast, stupid compiler!" In that context, casts are bad. Otherwise they are usually good, especially when you are trying to avoid the very subtle yet common bugs caused by C/C++ implicit integer promotion and balancing.
    – user29079
    Commented Oct 27, 2011 at 13:46
  • 2
    I'll concede that a design that requires a heavy use of casting is bad. But I won't concede that casts themselves are bad, or that a programmer who uses them is doing something bad. For example, if you read from a weakly-typed DataTable in .NET into certain variables, you'll likely be using casts a lot -and that's fine- even though the design which caused you to use those casts in the first place might not be the best. Commented Oct 27, 2011 at 14:16
1

When asking "why," it is important to ask two sub-questions. What does this gain us, and what does this lose us?

  1. What does this gain us?

Nothing, actually. I would guess you want to cut down on copy paste. That's an admirable goal, but the idiomatic C# way to write this is actually:

var drbObj = (DerivedClass)obj;
  1. What does this lose us?

Compile-time checks on runtime safety. The compiler usually doesn't know for sure that obj will always hold a reference to an instance of the derived class. It also doesn't know whether you are willing to risk an uncaught type-casting exception here. It doesn't know how to handle this situation at compile time.

When you put in the explicit cast, you are resolving that problem. You are explicitly telling the compiler, "I know that there is a DerivedClass instance in here, and I am willing to suffer an exception if I'm wrong." The compiler then does what you told it. It would be quite risky (runtime crashes without warning? no thanks!) to let the compiler decide to do that on its own.

0

The C# language uses casting syntax to mean a number of different things, depending upon the operand and result types. The meaning here is "I think the operand is a reference to a thing of type X, and I would like to make it available to something requiring a reference of type X; throw an exception if the thing isn't of the proper type.

When trying to write any sort of sane code, it's important to have at least some kinds of statements which can be guaranteed not to throw any exception unless a thread is rudely aborted. Given a local variable x of some reference type, it's important that if the evaluation of some expression can be guaranteed not to throw an exception, so can the statement x = expression;.

If x is of a type more derived than y, the expression (typeOfX)y; might throw an exception if y cannot be cast to the type of x, but the statement x = (typeOfX)y; obeys the rule that an assignment to a local variable cannot throw an exception once the evaluation of the right-hand argument is complete. Since downcasts are a situation where exceptions might get thrown, requiring a programmer to write x = (typeOfX)y; rather than just x = y; makes clear that the statement might throw an exception.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.