Fix For Default Parameter Value Not Compile Time Constant Error

Fix For Default Parameter Value Not Compile Time Constant Error Banner

Introduction

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 constant time constants.

Summary Video

What is a Compile Time Constant?

Values that are known and assigned at the time when the progrma 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 constain. 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 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 function call does not pass anything 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 a argument to the optional paramter.

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 a object or struct type.For example, if DATETIMECONSTANT was definied as a global variable and then there was a parameter 'DateTime myDate = DATETIMECONSTANT' This is invalid and the code will throw an compile error because the value will change at different types when you compile. It is not a constant value.

DateTime DATETIMECONSTANT = DateTime.Now;

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

This is a invalid use of 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 struct. A structs default value is when all of members are at their default values. In this case, we can use default keyword and this lets the compile know to use the default Color value which will initialize all the structs 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

Fix for 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 setting 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

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 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 paramter for the DateTime object. This is like Color is also a struct type. So in order for DateTime to have a default state all it’s variables inside the struct also need to be in their default state. We can see below the follow code snippet and image that show default values for the DateTime struct. 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 for code snippet for updated.

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 in 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? Cellections also need a compile time constant as well when used an optional parameter.

Look at the below exmaples. 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 then assign each of the collections to empty at the begginning 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 best way to solve this compile error if .NET version is greater than 7.1 one. 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 to use a function overload would be best.

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

Get Latest Updates
Comments Section