Atrotygma
Atrotygma

Reputation: 1153

Condition-depending property assignment

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:

Class definition

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; }
}

Execution

ClassA a = null;
ClassB b = new ClassB();

(a == null ? (BaseClass)b : a).BaseProperty = "What would Jon Skeet think about this?";
Console.WriteLine(b.BaseProperty);

Output

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

Answers (3)

Tim Schmelter
Tim Schmelter

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.

  • If x has type X and y has type Y then
    • If an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
    • If an implicit conversion (§6.1) exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
  • Otherwise, no expression type can be determined, and a compile-time error occurs.

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

Jon Skeet
Jon Skeet

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

dmay
dmay

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

Related Questions