Wednesday, 28 August 2013

7 Things you should know in Advanced .Net


            In my first .Net 3.5 framework project back in 2011, I wasn’t aware of LINQ or any of the cool features of .Net 3.5. Architect of that project was very well versed in the framework and its new features. He used to write code which has very few lines. I used to envy him because am used to FOR LOOP statement and he implement those logic using LINQ which was super cool. 

His code was stylish, sexy and had very few lines. So I learnt LINQ and other new features at that time. After learning LINQ and generics, I had knowledge of the new feature existence but very few features are used everyday, so I put together 7 things that make our life easier.
 People who have worked in 2.0 and earlier version will like this 7 things more.

Let Keyword    


            LET can be used inside the LINQ query. It can be used in places where you need to have EXPRESSION THAT CAN BE REUSED

Syntax: let identifier = expression


          
           int[] array = { 1, 3, 5, 7, 9 };
           var result = from element in array
                        where element * 100 >= 500
                        select element * 100;

           foreach (var res in result)
                Console.WriteLine(res);
            int[] array = { 1, 3, 5, 7, 9 };
            var result = from element in array
                         let v = element * 100
                         where v >= 500
                         select v;

            foreach (var res in result)
                Console.WriteLine(res);



            In the above example the value of the array element has to be multiplied by 100 and its value should also be displayed and should also be used to filter items which is greater than 500. element * 100 is used in many places. "LET" comes to our rescue to handle this situation of using the expression without duplicating everywhere.


Delegate or Lambda - Passing function as argument


            Whenever we want to have certain set of operation that needs to be delegated (REMEMBER STRATEGY PATTERN) to different object we use the delegates. In C# we have delegate key word for passing the function as a parameter. We can use lambda expression too.

Example:
            Let us have a delegate which accepts two Boolean variable and returns integer value. For people new to delegates, think delegate as a function pointer in C world, where it can save the address of any function that satisfies the input parameters and return type (SAME SIGNATURE).

            In below case any function which has two Boolean input parameters and has an integer return type can be assigned to DiscountDelegate.

delegate int DiscountDelegate(bool x,bool y);


            Let’s have a class that consumes the DiscountDelegate which has method named Process whose parameter is DiscountDelegate.

In this method Process, discount is invoked, what happens here below is that the call is placed on the address of the discount and whatever the method resolves to the code will be executed.


                    class ShoppingCart{
                         public void Process(DiscountDelegate discount)
                         {
                           int magicDiscount = discount(true,false);
                         }
                   }
 


Now we will define a Calculate and Calculate1 functions which takes two parameters and return the integer value as below.   The method below can be assigned to the DiscountDelegate since it satisfies the condition of the DiscountDelegate signature.

class Calculator
    {
        public static int Calculate(bool marketing, bool sales)
        {
            int discount = 0;
            if (marketing)
            {
                discount = 5;
            }
            else if (sales)
            {
                discount = 10;
            }
            else
            {
               discount = 15;
            }
            return discount;
        }
        public static int Calculate2(bool marketing, bool sales)
        {
            int discount = 0;
            if (marketing)
            {
                discount = 25;
            }
            else if (sales)
            {
                discount = 30;
            }
            else
            {
                discount = 23;
            }
            return discount;
        }
    }



Since Calculate1 and Calculate2 satisfy the criteria of DiscountDelegate with two bool parameters and return type is integer, we can assign the Calculate to the discount.


        public static void DelegateExec()
        {
            new ShoppingCart().Process(new DiscountDelegate(Calculator.Calculate));
            new ShoppingCart().Process(new DiscountDelegate(Calculator.Calculate2));
        }



            Or we can use the lambda expression to have a better implementation of the code, check out the syntax below where the method definition is added while calling the Process method, which reduces the reusablility but the structure helps to define the implementation easily



                new ShoppingCart().Process((marketing, sales) =>
                {
                    int discount = 0;
                    if (marketing)
                    {
                        discount = 5;
                    }
                    else if (sales)
                    {
                        discount = 10;
                    }
                    else
                    {
                        discount = 15;
                    }
                    return discount;
                });
 

            Above code reduces class creation or method that has the actual implementation which decreases lots of classes piling up in our library. Welcome to the lambda world where your class file and lines of code gets reduced.

Type Parameter

           
 First let’s understand where we need Type parameters

  • Type parameters are used in places where there is need of heavy boxing activities.
  • It is used in places where you need to define a variable of type that changes as per the object that is calling it.

To understand more let’s take an example of saving a data in a two different forms.

·         XML file
·         Normal text file.

 In normal case we might have to create a common class that will take care of the type of class that needs to be created to pass the instance as parameter and have a variable instantiated based on the type that has been passed. This requires the variable to be instantiated in the calling side before passing this instantiation or must be taken care in the server side or any Factory method to create an instance which requires boxing. Instead we use the type parameter.

Let us have an IDataOperation that performs CRUD operations

                               public interface IDataOperation
                               {
                                   bool Update(string value);
                                   bool Insert(string value);
                                   bool Delete(string value);
                               }
For XML Operation

                               public class XMLOperations:IDataOperation
                               {
                                   public bool Update(string value)
                                   {
                                       return true;
                                   }
                                   public bool Insert(string value)
                                   {
                                       return true;
                                   }
                                   public bool Delete(string value)
                                   {
                                       return true;
                                   }
                              }


For Normal Text file operation

    public class FileOperation:IDataOperation
    {
        public bool Update(string value)
        {
            return true;
        }
        public bool Insert(string value)
        {
            return true;
        }
        public bool Delete(string value)
        {
            return true;
        }
    }


            Normal way is to instantiate the FileOperation and XMLOperations in DataAccess class which handles the save functionality of the data. Below is typical Factory method for creating an instance.

    public class DataAccess
    {
        public IDataOperation dataOperation { get; set; }
        public DataAccess(string type)
        {
           if (type == "XML")
            {
                dataOperation = new FileOperation();
            }
            else if (type == "file")
            {
                dataOperation = new XMLOperations();
            }
         }
    }


Instead we can use the type parameter class and the instance will be created at run time based on the caller.

    
    public class DataAccess : IDataOperation where T : IDataOperation
    {
        public T dataOperation { get; set; }

        public DataAccess()
        {
            dataOperation = Activator.CreateInstance();
        }
        public bool Update(string value)
        {
            return dataOperation.Update(value);
        }
        public bool Insert(string value)
        {
            return dataOperation.Insert(value);
        }
        public bool Delete(string value)
        {
            return dataOperation.Delete(value);
        }
    } 


In the above example the T is parameter of type IDataOperation and so it will be evaluated at runtime, which saves the overhead of creating the instance and boxing those instances. So to consume the methods, you need to send the dataOperation type when creating the instance of the object as Type Parameter.


                DataAccess xml = new DataAccess();

        private static void doXMLOperations()
        {
            DataAccess xml = new DataAccess();
            xml.Insert("Input");
            xml.Update("Input");
            xml.Delete("Input");
        }
        private static void doFileOperations()
        {
            DataAccess file = new DataAccess();
            file.Insert("Input");
            file.Update("Input");
            file.Delete("Input");
        }


Thus we get the value of the object at run time and no boxing required, which saves lots of code and also the code looks elegant.

Anonymous Type


            This is one of the sweet features of C# 3.5. When we need set of properties that needs to be used only once without having to create a new class file which contains the properties. 

Syntax for the anonymous method is pretty simple and self-explanatory.

 
                return new
                {
                    Name = "apple",
                    Age = 2,
                    Weight = 150.50
                };


       Coolest thing about the anonymous type is we don’t have to describe any type of the property that is defined in the anonymous type. It is resolved @ runtime, which will be very useful when we need to pass value to another interface whose information is not known. Above example can be used in passing data to web layer as it is and can be consumed by Ajax call as a JSON object after normal data contract serialization.

 Co-Variance and Contra-Variance

First, let’s see what is Variance, Variance is about being able to use an object of one type as if it were another in a type safe way.

Covariance is all about values being returned from an operation back to the caller. Think of Covariance as OUT modifier. In the below example the string is defined and its value is being assigned into less derived type

// Covariance
string str = "test";
// An object of a more derived type is assigned to an object of a less derived type.
object obj = str;

Contra variance is opposite way around, it’s about values being passed by the caller and callee consumes the value instead of producing them. Think of Contra-variance as IN Modifier.

// Assignment compatibility.
object obj = "test";
string str = obj;

In above example, an object that is instantiated with a more derived type argument and is assigned to an object instantiated with a less derived type argument.

Why I need to know about variance.

 

            We need to know about variance is for one reason, how the compiler will behave in a particular scenario. Whether it will compile or it throws runtime exception for particular situation. In the below list the covariance and contra-variance support exists in the following tabular list. If you know what type of variance is supported, then you will know what type to consume and which type to assign.


IEnumerable<Derived> d = new List<Derived>();
                              IEnumerable<Base>      b = d;

 
Since you know IEnumerable<T> is covariant we can assign the derived class to base component. Knowing these information helps us to know which to use as an OUT and IN respectively. Below shows the list of Types and their variances.

If you want, one thing to remember about variance is, IEnumerable and Func are covariant, so we can assign derived class to base component.


Type
Covariant type parameters

Contravariant type parameters

Action<T> to Action<T1, T2, T3, T4 >


Yes
Comparison<T>

Yes
Converter<TInput, TOutput>

Yes
Yes
Func<TResult>
Yes

Func<T, TResult> to Func<T1, T2, T3, T4, TResult>
Yes
Yes
IComparable<T>

Yes
Predicate<T>

Yes
IComparer<T>

Yes
IEnumerable<T>
Yes

IEnumerator<T>
Yes

IEqualityComparer<T>

Yes
IGrouping<TKey, TElement>
Yes

IOrderedEnumerable<TElement>
Yes

IOrderedQueryable<T>
Yes

IQueryable<T>
Yes





 To understand in depth and its mathematical notation, click here

Extension

 

            Extension is one of the cool features that is available in Advanced C# (3.0 and above).  This one functionality has reduced number of lines of code in every project. For example, if we need to format a string in the project consistently in many places we need to call a method of static class that accepts input and gives us the formatted string.Here we can also see using Interface with Extension

Extension solves the problem by having an class and having all the needed transformation for the data type that are extended. Any type can be extended. If the type is extended then the extended method will part of the type where it will accessible just by referencing its namespace.

Define a static method inside static class and the first parameter must be this.

public static class MyExtensions
    {
        public static string ToCurrenyFormat(this string val,string format)
        {
            var CurrencyMark = format == "IND" ? "Rs": "$";
            return string.Format("{0} {1}", val, CurrencyMark);
        }
    }



First parameter must be this and followed by <Type> that needs to extended and it can be followed by any number of input parameters you want.  


      In above method, string is being extended with the name ToCurrenyFormat, look image below now where you can see the ToCurrenyFormat in the intellisense list.



return “1000”.ToCurrenyFormat("US");
return “1000”.ToCurrenyFormat("IND");

You can also extend interface. Syntax and Concept are same. Define a static method inside static class and the first parameter must be this.

 
            public interface ITestInterfaceExtension
            {
             string myMethod();
            }
            public static string InterfaceExtension(this ITestInterfaceExtension  value)
            {
                return "FOO";
            }

            In the above method we have extended the ITestInterfaceExtension, so going forward when we have to implement the InterfaceExtension for ITestInterfaceExtension. This can be used in places where the interface is got from the source where its source code is not editable, but we want another method to be implemented as part of the code. Extension can be used in places for all types. Since interface is a type, it can also be extended.


Optional Parameter


            Optional parameters are one of the new features in .Net 4.5, which has been a long wait. If you are aware of optional parameters in SQL server, then this feature exactly does the same here. This avoids overloading methods only reason being  a new parameter is needed, just because your business requirement changed. When optional parameters are defined, old method call will function as it is and new one can use the updated parameter.

In the below method value is the mandatory parameter and value1 is the optional parameter, where we give assign default value to value1

 
        public static bool OptionalParameterMethod(string value, string value1 = null)
        {
            return true;
        }

The trick lies in calling the optional parameter, the optional parameter must be add to the end and it cannot supersede the mandatory parameter

 
        public static void CallNamedArgumentMethod(string s)
        {
            OptionalParameterMethod("ABC");
            OptionalParameterMethod(value1: "ABC", value: "ASDF");
            OptionalParameterMethod("ABD", value1: "LKJH");
            // Positional arguments cannot follow named arguments.
            // The following statement causes a compiler error.
            //OptionalParameterMethod(value1:"ABD",  "LKJH");
        }

            In the first example the OptionalParameterMethod is called with only one parameters and the s2 is ignored so the value null will be taken.

OptionalParameterMethod(s1:"ABD",  "LKJH");  will show you a compile error and because the positional argument cannot follow named argument, so try to give the positional argument at the last and it should be resolvable or do not provide any value

            All the above listed features, such as Need for covariance and Contra-variance, Extension, Optional parameters, Anonymous Types, Type Parameters and Let keyword are all my favorite things about advanced C#, but there are much more than that, but what I have listed is the one we can use daily in our coding activities. Please comment below, the feature you find interesting in Advanced C#

Leave a comment to share what you learned, and hit the “like” button to let others know about it (make sure you’re logged into Facebook to like and comment). 

No comments:

Post a Comment

Note: only a member of this blog may post a comment.

Build Bot using LUIS