void Foo (int x = 24) {Console.WriteLine(x) }
Optional parameters can be omitted when calling the method:
Foo(); // 24
The default argument of 24 is actually passed to the optional parameter x - the compiler
bakes the value into the compiled code at the calling side - it substitutes the
default value of an optional parameter whenever it is used.
The default value of an optional parameter must be specified by a constant expression
or a parameterless constructor of a value type. Optional parameters cannot be
marked with ref or out.
Mandatory parameters must occur before optional parameters in both the method declaration
and the method call, the exception being params arguments, which must always
come last.
What this does is allow us to modify the effective signature and business logic of
a method by adding one or more optional parameters, without having to change
any legacy code calling the method. Here's a short example to illustrate.
Say I have a method GetOpenConnection() that is called from many places in my code.
It delivers a connection based on an element in the connectionStrings section
of the configuration file. The method originally had an overload where you can
specify the connection string name:
GetOpenConnection("connection1").
But let's say now that in one application that I intend to distribute, I don't
want users poking around in my config file getting my connection info, so I have
decided to bake my connection string into the code as a static property. (Nevermind
that I can encrypt the connectionStrings section - in this case I don't even
want to have a configuration file).
Here's the sample Stuff class that holds my connection string (and whatever else
I might want in there):
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
namespace StaticProperties
{
public static class Stuff
{
public static string ConnectionString
{
get { return "server=127.0.0.1;database=Northwind;Integrated Security=SSPI"; }
}
public static SqlConnection GetOpenConnection(string name, bool isMetaData = false)
{
string connectionString = String.Empty;
if (!isMetaData) // if default, get from config file
connectionString = ConfigurationManager.ConnectionStrings[name].ConnectionString;
else // not default, get from static class
connectionString = Stuff.ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
return conn;
}
public static string GetPropertyValue(Type myType, string propertyName)
{
PropertyInfo[] properties = myType.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo property in properties)
{
if (property.Name == propertyName)
{
return (string)property.GetValue(myType, null);
break;
}
}
return null;
}
}
You can see that I have a readonly ConnectionString property, a GetOpenConnection
method with a string name and optional isMetaData property, and a utility GetPropertyValue
method that allows the user to just get the value of a named string property
from a type.
Here's the calling code:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
namespace StaticProperties
{
class Program
{
static void Main(string[] args)
{
string conn = Stuff.GetPropertyValue(typeof (Stuff), "ConnectionString");
Console.WriteLine("From GetPropertyValue:\r\n " +conn);
using (SqlConnection connection= Stuff.GetOpenConnection("config"))
{
Console.WriteLine(" From Config (name only):\r\n " +connection.ConnectionString);
}
using (SqlConnection connection2 = Stuff.GetOpenConnection("config", true))
{
Console.WriteLine("From Stuff (IsMetaData=true):\r\n "+ connection2.ConnectionString);
}
Console.ReadLine();
}
}
}
First, we show getting the string using the GetPropertyValue method. Next, we show
using the name of a config element. Since we didn't specify a value for the
optional isMetaData parameter, its value will be false (the default) and the
method will return the connection specified in the config file.
But now, I have no configuration file. So in the third method call, I specify "true"
for the optional parameter, and the business logic of the method says "Oh-
I'm supposed to get this guy from my own property value in this class" - and so it ignores
the name parameter and does it's thing.
The bottom line is that all the hundreds of method calls that don't use this
feature do not need to be changed at all.
You can download the sample Visual Studio 2010 Console Application here.