Fix For C# Default Parameter Value Not Compile Time Constant Error

Fix For Default Parameter Value Not Compile Time Constant Error Banner

Introduction

In C#, this compile exception ‘CS1736: Default parameter value must be a compile-time constant’ occurs when you try to assign a optional parameter value that is not a constant or is not the correct default value. It works with numerical data types and strings in the list of parameters but not for objects or structs. Different objects have different default values and it is important to know which ones are valid parameter values to use on a given type. To understand this further, I will first tell you about compile time constants.

Video With Examples

What is a Compile Time Constant?

Values that are known and assigned at the time when the program is compiled and do not change are constant. Bool, numeric or string values can be constant at compile time and do not change even when the program runs. Numeric values or string values are constant at compile and remain constant. The const keyword can be added to create a compile-time constant. Below are some examples.

const double multiplier = 32;
const int hours = 19;
const string userName = "MyUserName";

Only built-in types can be marked as constant, such as numbers such as int, float, double, char, bool, and strings.

What Are Default Values of a Parameters?

Default values are values assigned to optional parameters in the function declaration. If the function call does not pass anything of those optional parameters then the default value will be assigned automatically to the optional parameter. Every optional parameter has to have a default value, in case the function call does not pass an argument to the optional parameter.

public void StartCountDownTimer(int hours = 6, int minutes = 40, int seconds = 30)
{
    // some logic
}
public void MathamicalFormulaFunction(double multiplier = 32)
{
    //some logic
}
public void LogDebugStatements(string log = "Debug")
{
    //some logic
}

These examples are valid uses for optional parameters for these datatypes because the value will still be the same at compile time and run time.

You can not assign any variable to the optional parameter if it is an object or struct type. For example, if DATETIMECONSTANT was defined as a global variable and then there was a parameter 'DateTime myDate = DATETIMECONSTANT' This is invalid and the code will throw a compile error because the value will change at different times when you compile. It is not a constant value.

DateTime DATETIMECONSTANT = DateTime.Now;

public void MyDateTimeFunction(DateTime myDate = DATETIMECONSTANT)
{
    //some logic
}

This is an invalid use of an optional parameter and will IDE will flag this as an error.

Struct Color Example

cs1736 default parameter value for datetime must be a compile time constant

This current code creates a graphics image with randomly generated points, but if I try to add a default value or optional parameter, then I get the following exception message. Color is not a built-in type and so we need to assign it to the correct default value or change it to a nullable type.

CS1736: Default parameter value for 'color' must be a compile-time constant

It is coming from Color color = Color.Aqua

private static void AddPoints(Graphics graphics, Color color = Color.Aqua)
{
    using (SolidBrush brushColor = new SolidBrush(color))
    {
        for (int i = 0; i < 100; i++)
        {
            Size iconSize = new Size(PointWidth, PointHeight);
            int randomX = GenerateRandomInt(ImageWidth);
            int randomY = GenerateRandomInt(ImageHeight);
            PointF pointF = new PointF(randomX, randomY);
            RectangleF rect = new RectangleF(pointF, iconSize);
            graphics.FillEllipse(brushColor, rect);
        }
    }
}

Color with Default Keyword Solution

As you can see Color.Aqua is not the correct default type for the struct. A struct's default value is when all of the members are at their default values. In this case, we can use the default keyword and this lets the compile know to use the default Color value which will initialize all the struct members to default values. In C# 7.1 and greater versions, you can use the default literal.

Color myColor = default; Default for Color is shown below.

struct color default value

The fix for the Color by-default keyword is below.

private static void AddPoints(Graphics graphics, Color color = default)
{
    if (color != null)
    {
        using (SolidBrush brushColor = new SolidBrush(color))
        {
            for (int i = 0; i < 100; i++)
            {
                Size iconSize = new Size(PointWidth, PointHeight);
                int randomX = GenerateRandomInt(ImageWidth);
                int randomY = GenerateRandomInt(ImageHeight);
                PointF pointF = new PointF(randomX, randomY);
                RectangleF rect = new RectangleF(pointF, iconSize);
                graphics.FillEllipse(brushColor, rect);
            }
        }
    }
}

Color with Nullable Solution

Another solution to this is to change the parameter Color to Color? which is a nullable type in .NET 6 and above and then set it to equal null. Null is a default value then the compiler will allow this type of optional parameter. This is changed to the following in the function.

The updated line is changed to 'Color? color = null'

private static void AddPoints(Graphics graphics, Color? color = null)
{
    if (color != null)
    {
        using (SolidBrush brushColor = new SolidBrush(color.Value))
        {
            for (int i = 0; i < 100; i++)
            {
                Size iconSize = new Size(PointWidth, PointHeight);
                int randomX = GenerateRandomInt(ImageWidth);
                int randomY = GenerateRandomInt(ImageHeight);
                PointF pointF = new PointF(randomX, randomY);
                RectangleF rect = new RectangleF(pointF, iconSize);
                graphics.FillEllipse(brushColor, rect);
            }
        }
    }
}
Full Code Color Sample
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace GraphicsToImage
{
    class Program
    {
        static int PointWidth = 10;
        static int PointHeight = 10;
        static int ImageWidth = 256;
        static int ImageHeight = 256;
        static void Main(string[] args)
        {
            using (Bitmap buffer = new Bitmap(ImageWidth, ImageHeight))
            {
                using (Graphics graphics = Graphics.FromImage(buffer))
                {
                    AddPoints(graphics, Color.AliceBlue);
                }
                buffer.Save(@"C:\temp\MyImage.png", ImageFormat.Png);
            }
        }
        private static void AddPoints(Graphics graphics, Color color = default)
        {
            if (color != null)
            {
                using (SolidBrush brushColor = new SolidBrush(color))
                {
                    for (int i = 0; i < 100; i++)
                    {
                        Size iconSize = new Size(PointWidth, PointHeight);
                        int randomX = GenerateRandomInt(ImageWidth);
                        int randomY = GenerateRandomInt(ImageHeight);
                        PointF pointF = new PointF(randomX, randomY);
                        RectangleF rect = new RectangleF(pointF, iconSize);
                        graphics.FillEllipse(brushColor, rect);
                    }
                }
            }
        }
        private static void AddPoints(Graphics graphics, Color? color = null)
        {
            if (color != null)
            {
                using (SolidBrush brushColor = new SolidBrush(color.Value))
                {
                    for (int i = 0; i < 100; i++)
                    {
                        Size iconSize = new Size(PointWidth, PointHeight);
                        int randomX = GenerateRandomInt(ImageWidth);
                        int randomY = GenerateRandomInt(ImageHeight);
                        PointF pointF = new PointF(randomX, randomY);
                        RectangleF rect = new RectangleF(pointF, iconSize);
                        graphics.FillEllipse(brushColor, rect);
                    }
                }
            }
        }
        private static int GenerateRandomInt(int max)
        {
            Random random = new Random();
            int randomNumber = random.Next(0, max + 1);
            return randomNumber;
        }
    }
}

Struct DateTime Example

cs1736 default parameter value for datetime must be a compile time constant

This following code example takes in a DateTime object and converts it into a timestamp string. It currently trying to assign an optional parameter for getting the current time if no dateTime is provided and we get the error.

CS1736: Default parameter value for 'dateTime' must be a compile-time constant

CS1736 error is coming from 'DateTime dateTime = DateTime.Now' in line 1.

public static string GenerateTimeStamp(DateTime dateTime = DateTime.Now)
{
    string timeStamp = $"{dateTime.Year}{dateTime.Month}{dateTime.Day}{dateTime.Hour}{dateTime.Minute}{dateTime.Millisecond}";
    return timeStamp;
}

DateTime with Default Keyword Solution

DateTime.Now is not the correct default parameter for the DateTime object. This is like Color is also a struct type. So for DateTime to have a default state all its variables inside the struct also need to be in their default state. We can see below the following code snippet and image that show default values for the DateTime struct. The default keyword is available in C# 7.1 and above.

DateTime defaultDateTime = default;
struct color default value

Fix for DateTime by default keyword is below

public static string GenerateTimeStamp(DateTime? dateTime = null)
{
    if (dateTime != null)
    {
        string timeStamp = $"{dateTime.Value.Year}{dateTime.Value.Month}{dateTime.Value.Day}{dateTime.Value.Hour}{dateTime.Value.Minute}{dateTime.Value.Millisecond}";
        return timeStamp;
    }
    else
    {
        return "";
    }
}

DateTime with Nullable Solution

A simple solution also be to change the DateTime type to a nullable type of DateTime?. This will allow us to set the optional parameter to null is technically a constant. See the following code snippet for updates.

public static string GenerateTimeStamp(DateTime? dateTime = null)
{
    string timeStamp = $"{dateTime.Value.Year}{dateTime.Value.Month}{dateTime.Value.Day}{dateTime.Value.Hour}{dateTime.Value.Minute}{dateTime.Value.Millisecond}";
    return timeStamp;
}

DateTime With Function Overload Solution

Starting with the most basic is the function overload method. This can be used in any of the .net versions. It takes two functions which one will call another. As you can see this first method which doesn't have parameters will call one that has a datetime parameter. We can pass the DateTime.Now to this other function that will give to us.

public static string GenerateTimeStamp()
{
    return GenerateTimeStamp(DateTime.Now);
}
public static string GenerateTimeStamp(DateTime dateTime)
{
    string timeStamp = $"{dateTime.Year}{dateTime.Month}{dateTime.Day}{dateTime.Hour}{dateTime.Minute}{dateTime.Millisecond}";
    return timeStamp;
}
Full Code DateTime Sample
using System;
namespace DateTimeDefaultParameter
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime dateTime = DateTime.Now;
            Console.WriteLine($"The Current TimeStamp is {GenerateTimeStamp(dateTime)}");
            Console.WriteLine($"The Current TimeStamp is {GenerateTimeStamp()}");
        }

        public static string GenerateTimeStamp(DateTime dateTime = DateTime.Now)
        {
            string timeStamp = $"{dateTime.Year}{dateTime.Month}{dateTime.Day}{dateTime.Hour}{dateTime.Minute}{dateTime.Millisecond}";
            return timeStamp;
        }

        public static string GenerateTimeStamp(DateTime dateTime = default)
        {
            string timeStamp = $"{dateTime.Year}{dateTime.Month}{dateTime.Day}{dateTime.Hour}{dateTime.Minute}{dateTime.Millisecond}";
            return timeStamp;
        }

        public static string GenerateTimeStamp(DateTime? dateTime = null)
        {
            if (dateTime != null)
            {
                string timeStamp = $"{dateTime.Value.Year}{dateTime.Value.Month}{dateTime.Value.Day}{dateTime.Value.Hour}{dateTime.Value.Minute}{dateTime.Value.Millisecond}";
                return timeStamp;
            }
            else
            {
                return "";
            }
        }

        public static string GenerateTimeStamp()
        {
            return GenerateTimeStamp(DateTime.Now);
        }
        public static string GenerateTimeStamp(DateTime dateTime)
        {
            string timeStamp = $"{dateTime.Year}{dateTime.Month}{dateTime.Day}{dateTime.Hour}{dateTime.Minute}{dateTime.Millisecond}";
            return timeStamp;
        }
    }
}

Null-Coalescing Operator Solution

Now we have seen some single-object examples but what about some more complex objects? Collections need a compile-time constant as well when using an optional parameter.

Look at the below examples. They all get a compile error so this doesn't work.

void AddToCollection(List<string> collection = new List<string>() {"name","name2","name3"})
{
    //some logic
}
void AddToCollection(List<int> collection = new List<int>() { 1,2,3})
{
    //some logic
}
void AddToCollection(int[] array = new int[] {1,2,3})
{
    //some logic
}
void AddToCollection(Dictionary<string,string> collection = new Dictionary<string, string>() { { "nameKey1", "nameValue1" } })
{
    //some logic
}

But what we can do to get around the compile error is to set each of these lists to null and then assign each of the collections to empty at the beginning of each of the functions. This can be done by the null-coalescing operator and it's available in C# 8.0 Now see the solution once we add the null-coalescing operator.

void AddToCollection(List<string> collection = null)
{
    collection ??= new List<string>() { "name", "name2", "name3" };
    //some logic
}

void AddToCollection(List<int> collection = null)
{
    collection ??= new List<int>() { 1, 2, 3 };
    //some logic
}
void AddToCollection(int[] array = null)
{
    array ??= new int[] { 1, 2, 3 };
    //some logic
}

void AddToCollection(Dictionary<string, string> collection = null)
{
    collection ??= new Dictionary<string, string>() { { "nameKey1", "nameValue1" } };
    //some logic
}

Conclusion

Overall RankMethod.NET VERSION
1Default Keyword>= 7.1
2Nullable >= 6
3Null-Coalescing Operator>= 8.0
4Function Overload All

Using the default keyword is the best way to solve this compile error if the .NET version is greater than 7.1. If you have version 6 or greater then the next best option is to use a nullable. In addition to nullable using the null plus the null-coalescing operator for collection types is a great way to solve this issue. If you are using .NET 6 or less then using a function overload would be best.

Do you have any other ideas on how to solve this? Leave a comment.

Get Latest Updates