Gigi
Gigi

Reputation: 340

null-conditional, null-coalescing, enumerable and params keyword

I didn't know what better title to chose for the question as I don't know what's the problem. Consider the following small C# code:

static void Main(string[] args)
{
    F1(null);
}
public static void F1(int[] values)
{
    F2(1, values?[0] as object ?? new object[0]);
    F2(2, values?.Select(v => (object)v) ?? new object[0]);
    F2(3, values?.Select(v => (object)v).ToArray() ?? new object[0]);
}
public static void F2(int idx, params object[] values)
{
    Console.WriteLine($"count {idx}: '{values?.Count()}'");
}

It outputs:

count 1: '1'
count 2: '1'
count 3: '0'

Why the first 2 are 1? If I use the Immediate Window in Visual Studio, all the following are null:

values?[0]
null
values?.Select(v => (object)v)
null
values?.Select(v => (object)v).ToArray()
null

Upvotes: 1

Views: 65

Answers (1)

Sweeper
Sweeper

Reputation: 270758

As you might know, for a params parameter of type object[], you can either pass an expression of type object (which implicitly creates a object[] and the object you passed will be treated as an element of the array), or an expression of type object[] (which will be passed to the method "directly").

object[] x = new object[0];
object y = new object();
F2(1, x); // values?.Count() is 0
F2(2, y); // values?.Count() is 1

Notably, this depends on the compile-time type of the expression only (unless there is dynamic stuff going on). Therefore, an expression of type object will be wrapped in an array, even if the expression evaluates to an object[] object at runtime.

object z = new object[0];
F2(3, z); // values?.Count() is 1

With that in mind, it should be clear why your code behaves like that. Both of these expressions are of type object:

values?[0] as object ?? new object[0]
values?.Select(v => (object)v) ?? new object[0]

values?[0] as object is of type object, and values?.Select(v => (object)v) is of type IEnumerable<object>. But the right hand side of ?? is of type object[]. So the whole expression is of type object in both cases.

In the case of

values?.Select(v => (object)v).ToArray() ?? new object[0]

values?.Select(v => (object)v).ToArray() is of type object[], the same type as new object[0], so the whole expression is of type object[].

Upvotes: 4

Related Questions