Reputation: 1153
Recently, I was rewriting some old code, especially shrink too long functions (reduce overhead, extend readability etc..). Thereby I stumpled about something that actually works:
public abstract class BaseClass {
public string BaseProperty { get; set; }
}
public sealed class ClassA : BaseClass {
public string PropertyA { get; set; }
}
public sealed class ClassB : BaseClass {
public string PropertyB { get; set; }
}
ClassA a = null;
ClassB b = new ClassB();
(a == null ? (BaseClass)b : a).BaseProperty = "What would Jon Skeet think about this?";
Console.WriteLine(b.BaseProperty);
What would Jon Skeet think about this?
Can someone explain to me how this works? What is this sorcery? Of course I can handle both instances the same way as they share a common base class, but I'm only casting one of them to the base class and I'm doing a property assignment based on a condition. Also, is this considered as a good practice or are there any significant downsides I just can't see?
Upvotes: 0
Views: 307
Reputation: 460128
You are using the conditional operator(?) similiar to this more redable if
:
if (a == null)
b.BaseProperty = "...";
else
a.BaseProperty = "...";
Console.WriteLine(b.BaseProperty);
The cast in this code
(a == null ? (BaseClass)b : a).BaseProperty = "..."
is just needed because the conditional operator needs to know the type. The type of the conditional expression must be consistent for both.
So in my opinion it's bad practise since it's not clear what you're doing.
Why the cast to BaseClass
is required: the relevant section of the C# 5.0 spec is 7.14, the conditional operator:
The second and third operands, x and y, of the ?: operator control the type of the conditional expression.
So since there is no implicit conversion between ClassA
and ClassB
(they have just the same base class), you have to cast it mnaually.
Upvotes: 1
Reputation: 1500535
Can someone explain to me how this works?
Sure - it's just an expression using the conditional operator to pick which value to use for the rest of the expression. The overall type of the expression is BaseClass
because that's the exact type of the second operand, and the third operand can be converted to it. You need the cast on one of the operands, because the overall type of the expression has to be either the type of the second operand or the type of the third operand... but neither ClassA
nor ClassB
are suitable.
Also, is this considered as a good practice or are there any significant downsides I just can't see?
Well it looks pretty ugly to me. I'd use the null-coalescing operator instead, and extract it into a separate local variable for clarity:
BaseClass target = a ?? (BaseClass) b;
target.BaseProperty = "Jon Skeet prefers this approach";
You could still do it in one statement, but I find that less readable:
(a ?? (BaseClass) b).BaseProperty = "Jon Skeet doesn't like 'clever' code.";
Even better would be to declare either a
or b
as being of type BaseClass
, at which point you don't need the cast.
Upvotes: 1
Reputation: 1325
(a == null ? (BaseClass)b : a)
is
BaseClass x = null;
if(a == null)
x = (BaseClass)b;
else
x = (BaseClass)a; // Here is implicit cast to the type of the second argument of ? operator
return x;
Upvotes: 1