Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

A Beginner's Tutorial on Extension Methods, Named Parameters, Optional Parameters, Object Initializers and Anonymous types in C#

4.78/5 (22 votes)
5 Apr 2013CPOL9 min read 50.5K   304  
In this article, we will discuss four very important features of C# programming language.

Introduction

In this article, we will discuss four new and very important features that have been introduced in the later versions of C#. Developers coming from an older version like C# 2.0 or perhaps those learning C# might find this article useful.

Background

C# is a language that is improving at a very fast pace. It is getting more and more features with every release. It came years after languages like C++ and Java but managed to surpass them in terms of language features and developer productivity.

In this small tutorial article, I will try to explain four very important features of C# programming language in my own way. This might not be very useful for those who are already aware of these features, but this article is meant for beginners who are still in the phase of learning C#.

We will be discussing the following four features of C# in this article. We will also write a sample application for each to see them in action.

  • Extension Methods
  • Named and Optional Parameters
  • Object Initializers
  • Anonymous types

Using the Code

Extension Methods

Open Closed Principle(OCP) states that we should design our types in such a way that it should be open for extension, but closed for modification. Extension methods in C# can be thought of as a mechanism to implement the OCP for user defined types or even the primitive types and the types defined in the framework.

Extension methods allow us to extend an existing type by adding additional methods and functionality to an existing type without needing to change the code of that type (we might even not have code in most cases). Prior to the existence of extension methods, developers used to create their own types and either inherit or contain the existing type inside these types. These new types were more of the wrappers on the existing types rather than the actual extensions of these types.

For example, if we needed to have the functionality of getting the negative of an integer, then I will have to wrap my integer in a custom type and then use this custom type to perform the operation.

C#
// Old way of extending using wrapper classes
struct MyInt
{
    int value;       

    public MyInt(int val)
    {
        this.value = val;
    }

    public int Negate()
    {
        return -value;
    }
}

static void Main(string[] args)
{
    // Old way of using wrappers for extensions
    MyInt i = new MyInt(53);
    Console.WriteLine(i.Negate());
}

Now this approach did work but the problem is that we are not at all extending the existing type. We are creating a new type all together that is wrapping the existing type and then providing us the desired functionality.

So if we really want to extend a method, we should be able to add this method Negate in the int type only and everyone should be able to call this method on int type only. No need to create another type to have this additional functionality. Extension methods provide just the same thing. Using extension methods, we can write the custom functionality and can hook them with the existing types so that they can be used on those types.

To create an extension method, we need to take the following steps:

  1. Define a static class.
  2. Define a public static function in this class with the name desired as the new method name and return value as per the functionality.
  3. Pass the parameter of type that you want to extend. The important thing here is to put a this keyword before the parameter to tell the compiler that we need to extend this type and we are not really expecting this type as argument.

So let's try to add this Negate function in the int type.

C#
// Extending using Extension methods
static class MyExtensionMethods
{
    public static int Negate(this int value)
    {
        return -value;
    }
}

static void Main(string[] args)
{
    //Using extension method
    int i2 = 53;
    Console.WriteLine(i.Negate());
}

Now using extension method, let us define the methods on some existing type. Now what if we want the new method to accept some parameters. Well to do this, we can define additional parameters after the first parameter that is of the type to be extended (used with this keyword. Let's define one more function in int called Multiply to see this in action.

C#
// Extending using Extension methods
static class MyExtensionMethods
{
    public static int Negate(this int value)
    {
        return -value;
    }

    public static int Multiply(this int value, int multiplier)
    {
        return value * multiplier;
    }
}

static void Main(string[] args)
{
    // Passing arguments in extension methods
    int i3 = 10;
    Console.WriteLine("Passing arguments in extension methods: {0}", i3.Multiply(2));
}

Now, there are two points that need to be remembered before implementing extension methods:

  • First of which is that the extension methods can only access the public properties of the type.
  • The extension method signature should not be the same as an existing method of the type.
  • The extension method for a type can only be used if the namespace that contains the extension method is in scope.
  • In case we define extension methods in such a way that it overloads an existing method of the original type and the calls are getting ambiguous, then the overload resolution rule will always choose the instance method over the extension method.
  • If there is some ambiguity between two extension methods, then the method containing more specific arguments will get called.

If we keep the following point in mind, we could really utilize the extension methods to better design and extend the types and provide better abstraction of the type. LINQ uses extension methods heavily. It is highly recommended to look at how LINQ used extension methods in conjunction with LAMBDA expression.

Note: Information on Lambda expressions can be found here: A Beginner's Tutorial on Basics of Delegates, Anonymous Functions and Lambda Expressions in C#[^].

Optional Parameters

Now before we go ahead and start talking about Named and positional parameters, let us talk a little about optional parameters. In older versions of C#, it was not possible to create optional parameters for functions, i.e., if I need to have default value of a parameter in a function, the only way to do that was the function overloading.

Lets say we want to define a function Multiply in which the caller can pass two numbers and get the result back. But if the user wants to pass only one parameter, then that is allowed too and the function will Multiply this number with 1 and return the value. Now in older versions of C#, this is done using function overloading as:

C#
private static int Multiply(int num1, int num2)
{
    return num1 * num2;
}

private static int Multiply(int num1)
{
    return Multiply(num1, 1);
}

static void Main(string[] args)
{
    // Testing OldWay of default parameters
    Console.WriteLine(Multiply(2));
}

Now this provided the desired result but the problem here is that as the number of function arguments increase, the number of overloaded functions will also increase to provide all possible combinations. Having a lot of overloaded version of function is a maintenance nightmare.

Now to solve this problem, C# introduced the provision of having optional parameters in functions. So using optional parameters, the above function will look like:

C#
private static int Multiply2(int num1, int num2 = 1)
{
    return num1 * num2;
}

static void Main(string[] args)
{
    // Testing default parameters
    Console.WriteLine(Multiply2(2));
}

The only limitation of having optional parameters is that the default parameters should always come after all the mandatory parameters in a function.

Named Parameters

Now having the possibility of having the optional parameter is great but there is one small problem, if we have multiple optional parameters in a function. Let's say we have a function like this:

C#
private void TestFunction(int one, int two, int three = 3, int four = 4, int five = 5)
{
    // Some implementation here
}

Now we want to pass the values of four and five but want to use the default value of three. This would not be possible under normal conditions. To perform this operation, we need to use the named parameters. Named parameters gives us the possibility of passing specific function argument with their names. So let's try to call this function.

C#
TestFunction(one: 11, two: 22, four: 44, five: 55);

Now calling the function like above, we use the default value of three and at the same time, pass the values for four and five, which are the optional parameters defined after three.

We have also used the named argument for variable one and two, but since we are passing one and two at their respective parameter positions, we can omit the names from them and thus, they will simply be passed as positional parameters and four and five as named parameters.

C#
TestFunction(11, 22, four: 44, five: 55);

Object Initializers

Object initializers in C# provides us with a simple way to initialize all the properties of objects at the time of construction only. Let's say we have a simple class with some public properties as:

C#
// A simple class to test object initializers
class Book
{
    public int BookID { get; set; }
    public string BookName { get; set; }
    public string AuthorName { get; set; }
    public string ISBN { get; set; }
}

Now let us create the object of this class using object initializers as:

C#
static void Main(string[] args)
{
    // using object initializers
    Book book = new Book
                {
                    BookID = 1,
                    BookName = "MVC Music Store Tutorial",
                    AuthorName = "Jon Galloway",
                    ISBN = "NA"
                };
}

A Note on Automatic Properties

Now the way I defined the class properties might be new for the guys using C# 2.0 or below. The properties are defined as automatic properties. If any variable of our class is only acting as a data store and has no validation logic before setting or getting it, then we can completely skip the creation of the variable and directly create the property. The compiler will take care of generating a variable for this property at run-time.

Implicitly Typed Variables and Anonymous Types

In C# 3.0 and above, we can define a variable without specifying its actual type provided that the variable is being assigned with some value. These variables are implicitly type, i.e., the type of the variable is the type of the variable that is being assigned to it.

C#
var var1 = new Dictionary<string, Book>();
var var2 = "some random string";
var var3 = Multiply(3, 4);

Now the type of the var1 is Dictionary<string, Book> because it is being created as that. The type of var2 is string because a string is being assigned to it and type of var3 is int because the function is returning a int.

var does not define a dynamic variable that can be assigned with any type. It is just a syntactic sugar so that we can skip defining the type of variable in local scope.

var is just a syntactic sugar, Having said that, there is one more thing that is important. We should try not to use the var keyword for declaring local variables because for which we can define explicit types. The reason for this is that it reduced readability of code. Now the question would be when to use var?

We should use var only when we have to. The only place we need to use var is with Anonymous types, i.e., types that are created on the fly and their type name is not available at compile time. LINQ queries often creates the need of creating Anonymous types and this is the only place we should use implicitly types variable, i.e., var.

Let us create a simple anonymous type, assign it and use it using implicitly typed variable.

C#
// Mandatory use of var, i.e., anonymous types
var aVar = new { Name = "Rahul", Age = 30 };
Console.WriteLine("{0} is {1} years of age", aVar.Name, aVar.Age);

Note: Anonymous type mandates the use of var keyword. For all other scenarios, it is not recommended to use var because of the above mentioned reduced readability problem. If LINQ projections are being used, then the use of var keyword is an absolute must.

Point of Interest

In this article, we talked about some features of C# that were introduced in C# 3.0. This article is meant for absolute beginners who are not aware of these features of C# and is written from an absolute beginner's perspective only. I highly recommend looking at the code to get a full understanding of all these features. I hope this has been informative.

History

  • 5th April, 2013: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)