SoFunction
Updated on 2025-03-07

Detailed explanation of the implementation of the "default parameters" of the new feature of C# 4.0

Preface

I believe everyone is familiar with the new features of C# 4.0. The so-called default parameter, as the name implies, is to specify a default value for a certain parameter of the method when declaring it. If the default value is used when calling the method, you do not need to specify the parameter. Like many language-level features (synonym sugar), the default parameters are also a trick that the compiler plays for us. The default parameters are ultimately reflected in two special custom features, OptionalAttribute and DefaultParameterValueAttribute.

Table of contents

  • 1. Usage of default parameters
  • 2. Implement two characteristics of default parameters: OptionalAttribute and DefaultParameterValueAttribute
  • 3. Define the default parameters directly through OptionalAttribute and DefaultParameterValueAttribute

1. Usage of default parameters

For example, the following TestMethod method, the next two parameters bar and baz are the default parameters, and the default values ​​are "Bar" and "Baz" respectively.

  1: static void TestMethod(string foo, string bar = "Bar", string baz = "Baz")
  2: {
  3:   ("{0, -5} - {1, -5} - {2, -5}", foo, bar, baz);
  4: } 

When calling TestMethod, we freely choose to use the default parameter value or override the default value.

  1: static void Main(string[] args)
  2: {
  3:   TestMethod("Foo");
  4:   TestMethod("Foo", "Bar1");
  5:   TestMethod("Foo", "Bar1", "Baz1");
  6: }

Here is the output result:

   1: Foo   - Bar   - Baz
   2: Foo   - Bar1  - Baz
   3: Foo   - Bar1  - Baz1

There are two simple limitations in the use of default parameters. One is: the declaration of default parameters can only be placed after ordinary parameters. In the TestMethod method defined in the following code, the default parameter bar is followed by a non-default parameter baz. Such code cannot be compiled (the compilation error message is: Optional parameters must appear after all required parameters).

  1: static void TestMethod(string foo, string bar = "Bar", string baz)
  2: {
  3:   ("{0, -5} - {1, -5} - {2, -5}", foo, bar, baz);
  4: }  

However, the default parameters can be followed by array parameters (params parameters). In fact, no matter what the situation is, the params parameter can only be the last declared parameter. It is easy for everyone to understand the location limitations of the declaration of default parameters and the identification mechanism of the main overload method.

Another limitation of the default parameter is that the specified default value must be a constant, which actually limits the data type as the default parameter - only the system-defined primitive type. In the TestMethod method defined below, we define a default parameter of DateTime type and use the default value of the parameter as. Since it is not a constant, such code cannot be compiled (compile error message: Default parameter value for 'date' must be a compile-time constant).

  1: static void TestMethod(DateTime date = )
  2: {
  3:  //Others...
  4: }  

2. Implement two characteristics of default parameters: OptionalAttribute and DefaultParameterValueAttribute

Why can the default value of the default parameter only accept constants? If you understand the nature of the default parameters, this is not a problem. So how are the default parameters implemented?

Like many language-level features (synonym sugar), the default parameters are also a trick played by the compiler for us, and the things that are actually compiled are all things that we are most familiar with. When the C# code containing the default parameters is compiled, the default parameters are reflected in two special custom characteristics, OptionalAttribute and DefaultParameterValueAttribute. The former identifies the parameter as a default parameter, and the latter specifies its default value.

  1: [ComVisible(true), AttributeUsage(, Inherited=false)]
  2: public sealed class OptionalAttribute : Attribute
  3: {
  4: }
  5: 
  6: [AttributeUsage()]
  7: public sealed class DefaultParameterValueAttribute : Attribute
  8: {
  9:   public DefaultParameterValueAttribute(object value);
 10:   public object Value {get; }
 11: }

For the TestMethod method we defined at the beginning, the compiled form is as follows.

  1: private static void TestMethod(string foo, 
  2:   [Optional, DefaultParameterValue("Bar")] string bar, 
  3:   [Optional, DefaultParameterValue("Baz")] string baz)
  4: {
  5:   //Others..
  6: }

It is precisely because the default value of the default parameter ends up being a parameter of the DefaultParameterValueAttribute that it must be a constant.

3. Define the default parameters directly through OptionalAttribute and DefaultParameterValueAttribute

Since the default parameters are ultimately reflected in the two characteristics of OptionalAttribute and DefaultParameterValueAttribute, can we directly define the default parameters through them? The answer is: Of course, the following code can be executed normally.

  1: static void Main(string[] args)
  2: {
  3:   TestMethod("Foo");
  4:   TestMethod("Foo","Bar1");
  5:   TestMethod("Foo","Bar1","Baz1");
  6: }
  7: 
  8: private static void TestMethod(string foo, 
  9:   [Optional, DefaultParameterValue("Bar")] string bar, 
 10:   [Optional, DefaultParameterValue("Baz")] string baz)
 11: {
 12:   //Others..
 13: }

If a method with default parameters is called and the specified parameter is not displayed, the compiler will automatically append the default value when compiling. For the above Main method, the following is the compiled code equivalent to it.

  1: private static void Main(string[] args)
  2: {
  3:   TestMethod("Foo", "Bar", "Baz");
  4:   TestMethod("Foo", "Bar1", "Baz");
  5:   TestMethod("Foo", "Bar1", "Baz1");
  6: }

Although we can also define default parameters through the two characteristics of OptionalAttribute and DefaultParameterValueAttribute, when we define the default parameters before the normal parameters, the compiler will not report an error. However, the default parameters in the method are actually equivalent to ordinary parameters.

  1: static void Main(string[] args)
  2: {
  3:   //TestMethod("Foo","Baz");
  4:   //The above method call is invalid  5:   TestMethod("Foo","Bar1","Baz1");
  6: }
  7: private static void TestMethod(string foo, 
  8:   [Optional, DefaultParameterValue("Bar")] string bar, 
  9:   string baz)
 10: {
 11:   //Others..
 12: }

Summarize

This is the end of this article about the implementation of the "default parameters" of the new C# 4.0 feature. For more related contents of the "default parameters" of the new C# 4.0 feature, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!