Tuesday 15 April 2014

Extension Method for Linq to process a user specified default value for FirstorDefault Method if value not exists

In this article we are going to see a Extension method which will use to process a user specified default value if value not exist or met the condition.This kind of default should be there not only for FirstorDefault method and also for another Linq methods can be applicable.

Actually when this idea is came to my mind i gave this as suggestion to the Microsoft to add a overloads for some of them Linq Methods

Suggestion posted in Microsoft as :

While select a Value from Collection using Linq , Using Following Methods First,Last Have Default,In that It is already returning the Default value for that Type if the value not exists in collections, Instead of that return Specify a Default of user specified value in the function parameter of the same type. for Example

List<string> coll=new List<string>();

var value = coll.FirstOrDefault();        // Returns null value if not exists in collection as default value

Instead of doing like this specify the user defined default value of same type

var Value=coll.FirstOrDefault("No"); // if default value specifies return that value if no value presents in collection , If default value not specifies then return default of that type .


Microsoft :

Posted by Microsoft on 2/16/2014 at 2:00 AM
Hey Rajhseg,

Nice suggestion! Nullable<T> has a GetValueOrDefault method which is parameterized similarly. We'll add it to our wishlist for future features. In the meantime for any collection type that has reference type or nullable value type elements a workaround would be to use the null-coalesce operator (??) like so:

List<string> coll = new List<string>();

var value = coll.FirstOrDefault() ?? "No";

This doesn't work for non-nullable value types though. Alternately as a workaround you could define such an extension method yourself. Something like:

internal static class MyLinqExtensions
{
        public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue) {
            if (source == null) throw new ArgumentNullException("source");
            IList<TSource> list = source as IList<TSource>;
            if (list != null) {
                if (list.Count > 0) return list[0];
            }
            else {
                using (IEnumerator<TSource> e = source.GetEnumerator()) {
                    if (e.MoveNext()) return e.Current;
                }
            }
            return defaultValue;
        }
}

This would handle any type. It's not as cool as having it just be part of LINQ but it's a convenient fix in the meantime. I'll see if we can add such overloads to FirstOrDefault and the other *OrDefault methods in the future.

Regards,
YYYYYYY | Program Manager | Visual Basic & C# Languages Team



Let we see a sample program how to use that extension method 

    internal static class MyLinqExtensions
    {
        public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
        {
            if (source == null) throw new ArgumentNullException("source");
            IList<TSource> list = source as IList<TSource>;
            if (list != null)
            {
                if (list.Count > 0) return list[0];
            }
            else
            {
                using (IEnumerator<TSource> e = source.GetEnumerator())
                {
                    if (e.MoveNext()) return e.Current;
                }
            }
            return defaultValue;
        }

    }


Implementation :

    class Employee
    {
        public string Name { set; get; }   

        public int Id { set; get; }

        public string Address { set; get; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Employee> emp = new List<Employee>();
            emp.Add(new Employee(){Address = "Chennai",Id =1,Name = "Rajesh"});
            emp.Add(new Employee() { Address = "Madurai", Id = 2, Name = "Siva" });
            emp.Add(new Employee() { Address = "Coimbatore", Id = 3, Name = "Suresh" });
            emp.Add(new Employee() { Address = "Chennai", Id = 4, Name = "Siva" });


            Employee e =emp.Where(x => x.Name == "Rajesh1").FirstOrDefault(new Employee(){Id = 0,Address = "Default",Name = "Default"});

            Console.WriteLine(e.Name);
            Console.Read();
        }

    }



In the above example you can see the there is no name Rajesh1 so the linq query normally return null as default but because of our extension method we can pass a user defined value as default.


Output:

    Default


From this article you can learn how to  process a user specified default value for FirstorDefault Method if value not exists

Monday 14 April 2014

What is the Difference between the Deep Clone and Shallow Copy - C#

In this article we are going to see about shallow copy and deep clone, first we have to knew what is cloning getting a new copy of particular object. i.e copy the non-static fields of the object.

             Student std = new Student("Rajesh", 1, 212,12);

Deep Clone :
    In this Deep clone it will create a new copy of that entire object , value types fields have a new copy and reference type field have a new copy by create a new instance.

it is very important that to perform a deep clone class must have a attribute [Serializableand set the memory stream to position 0 otherwise result in some error.


        public Student DeepClone()
        {
            MemoryStream ms = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(ms, this);
            ms.Position = 0;
            // if the above line is not there then error will raise as "End of Stream encountered before parsing was completed."
            return (Student)formatter.Deserialize(ms);
        }


              

                Student dc = std.DeepClone();


Shallow Copy :
   In the Shallow Copy it will create a new copy of that entire object using  MemberwiseClone method, Here the value types have a new copy and reference type field have a reference of that previous object instead of create a new instance.


        public Student ShallowCopy()
        {
            return (Student)MemberwiseClone();
               }


                Student shc = std.ShallowCopy();

you can see after get a copy object from shallow copy change the base object reference field value 
base object is std, now change the value of the value type field id and reference type field Depart. You can see the object that this changes can reflect only in the Shallow copy not in the Deep clone.


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace SampleApplication
{
    [Serializable]
    class Student
    {
        public static int Count { set; get; }

        public string Name { set; get; }

        public int Id { set; get; }

        public Department Depart { set; get; }

        public void Process()
        {
            Console.WriteLine("Processing");
        }

        public Student(string name,int id,int departid,int labs)
        {
            Name = name;
            Id = id;
            Depart = new Department(departid,labs);
        }

        public Student ShallowCopy()
        {
            return (Student)MemberwiseClone();
        }

        public Student DeepClone()
        {
            MemoryStream ms = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(ms, this);
            ms.Position = 0;
            // if the above line is not there then error will raise as "End of Stream encountered before parsing was completed."
            return (Student)formatter.Deserialize(ms);
        }

    }

    [Serializable]
    class Department
    {
        public int DepartmentId { set; get; }

        public Labs lab { set; get; }

        public Department(int department,int labs)
        {
            DepartmentId = department;
            lab =new Labs(labs);
        }
    }

    [Serializable]
    class Labs
    {
        public int Count;

        public Labs(int count)
        {
            Count = count;
        }
    }
     }

Program :

class Program
        {
            static void Main(string[] args)
            {
                Student std = new Student("Rajesh", 1, 212,12);
               
                Student shc = std.ShallowCopy();
                Student dc = std.DeepClone();
                shc.Process();
                dc.Process();
               
                Console.WriteLine();
                Console.WriteLine(" [Shallow Copy] Department Id " +shc.Depart.DepartmentId);
                Console.WriteLine(" [Deep Clone] Department Id "+dc.Depart.DepartmentId);
                Console.WriteLine(" [Shallow Copy] Department Labs " + shc.Depart.lab.Count);
                Console.WriteLine(" [Deep Clone] Department Labs " + dc.Depart.lab.Count);
               
                Console.WriteLine(" [Shallow Copy] Id "+shc.Id);
                Console.WriteLine(" [Deep Clone] Id "+dc.Id);


                std.Depart.DepartmentId = 4;
                std.Id = 2;
                std.Depart.lab.Count = 15;

                Console.WriteLine("\n Department id is changed from 212 to 4 , id 1 to 2, labs 12 to 15");
                Console.WriteLine();
                Console.WriteLine(" [Shallow Copy] Department Id " + shc.Depart.DepartmentId);
                Console.WriteLine(" [Deep Clone] Department Id " + dc.Depart.DepartmentId);
                Console.WriteLine(" [Shallow Copy] Department Labs " + shc.Depart.lab.Count);
                Console.WriteLine(" [Deep Clone] Department Labs " + dc.Depart.lab.Count);
                Console.WriteLine(" [Shallow Copy] Id " + shc.Id);
                Console.WriteLine(" [Deep Clone] Id " + dc.Id);
               

                Console.Read();
            }     

        }

Output:

Processing
Processing

 [Shallow Copy] Department Id 212
 [Deep Clone] Department Id 212
 [Shallow Copy] Department Labs 12
 [Deep Clone] Department Labs 12
 [Shallow Copy] Id 1
 [Deep Clone] Id 1

 Department id is changed from 212 to 4 , id 1 to 2, labs 12 to 15

 [Shallow Copy] Department Id 4
 [Deep Clone] Department Id 212
 [Shallow Copy] Department Labs 15
 [Deep Clone] Department Labs 12
 [Shallow Copy] Id 1

 [Deep Clone] Id 1



From this article you can learnt the difference and how to use the shallow copy and deep clone.