Search code examples
c#parameter-passingdefaultrecordenumerable

C# records constructor parameter default value empty IEnumerable


I am converting this class

public class MyClass
{
    public IEnumerable<string> Strings { get; }

    public MyClass(IEnumerable<string>? strings = null)
    {
        Strings = strings ?? new List<string>();
    }
}

To a record. Currently I have this:

public record MyRecord(IEnumerable<string>? strings = null);

However, I can't find a way to default initialize the IEnumerable to an empty enumerable, as it must be a compile time constant. I tried static initializing a readonly array, but same problem.


Solution

  • Since IEnumerable<string> is a reference type, the only possible default parameter is null. There's absolutely nothing else you can stick there. But! You can reference the property from the primary constructor in the initialization of an explicitly declared "long-form" auto-property. This would allow you to coalesce the value as it's assigned to the property.

    public record MyRecord(IEnumerable<string>? Strings = null)
    {
        public IEnumerable<string> Strings { get; init; } = Strings ?? Enumerable.Empty<string>();
    } 
    

    See SharpLab

    This actually generates a constructor for your record similar to the one you had originally. Here's what the above link generates (with the nullable attributes converted back to ?) for the constructor:

    public MyRecord(IEnumerable<string>? Strings = null)
    {
        <Strings>k__BackingField = Strings ?? Enumerable.Empty<string>();
        base..ctor();
    }
    

    It's a little more verbose/not as compact as the one-liner but it's the only way to accomplish what you ask for with a record and it's still shorter than the non-record version.

    Also note that if you look at the generated code, the property ends up being declared non-nullable, while the constructor parameter is nullable. Compare this to the single line version you started with, where the generated parameter would be nullable to match the primary constructor declaration. In this solution, you could change this behavior (if you needed to) and explicitly mark the long-form property nullable as well.