Skip to content

Instantly share code, notes, and snippets.

@RajaniCode
Last active December 17, 2019 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RajaniCode/342146d2c8e69d5eb1fef8f17fc13634 to your computer and use it in GitHub Desktop.
Save RajaniCode/342146d2c8e69d5eb1fef8f17fc13634 to your computer and use it in GitHub Desktop.
LINQ
// LINQ
using System; 
using System.Linq;  
using System.Collections;
using System.Collections.Generic;     
class Query
{
public void Print()
{
string[] array = { "Alpha", "Beta", "Gamma", "Delta", "Epsilon" };
IEnumerable<string> query = array.Where (x => x.Length > 5);
Console.WriteLine("Query");
foreach (string name in query)
{
Console.WriteLine (name);
}
Console.WriteLine();
// Chaining Query Operators
query = array.Where(x => x.Contains ("a"))
.OrderBy (x => x.Length)
.Select (x => x.ToUpper());
Console.WriteLine("Chaining Query Operators");
foreach (string name in query)
{
Console.WriteLine(name);
}
Console.WriteLine();
// Query Expressions
query = from x in array
where x.Contains ("a") // Filter elements
orderby x.Length // Sort elements
select x.ToUpper(); // Translate each element (project)
Console.WriteLine("Query expressions");
foreach (string name in query)
{
Console.WriteLine(name);
}
Console.WriteLine();
}
}
public class Developer 
{       
public string Name;       
public string Language;       
public int Year;  
}     
class WhereClause 
{
Developer[] developers = new Developer[] 
{
new Developer {Name = "Bill", Language = "C#"},               
new Developer {Name = "Larry", Language = "Kotlin"},               
new Developer {Name = "Tim", Language = "Swift"}
}; 
public void Print() 
{           
var devs = from d in developers
where d.Language == "C#" || d.Language == "Kotlin"            
select d.Name;
       
Console.WriteLine("Where clause");
foreach(var dev in devs) 
{              
  Console.WriteLine(dev);           
}
Console.WriteLine();    
}  
}
class FromClause
{
public void Print() 
{
   // From Clause
// A query expression against a nongeneric data source, with type declaration for the range variable
ArrayList developers = new ArrayList(); 
developers.Add(new Developer { Name = "Bill", Language = "C#" });  
developers.Add(new Developer { Name = "Larry", Language = "Kotlin" });  
developers.Add(new Developer { Name = "Tim", Language = "Swift" });
var devs = from Developer d in developers
where d.Language == "C#" || d.Language == "Swift" 
select d.Name;     
Console.WriteLine("From clause");
foreach (string dev in devs) 
{       
Console.WriteLine(dev);  
}
Console.WriteLine();
}
}
// A query expression with a join between two data sources
class Customer 
{      
public String Name { get; set; }       
public String City { get; set; }       
public Order[] Orders { get; set; }  
}  
  
class Order 
{       
public int OrderId { get; set; }       
public Decimal Amount { get; set; }       
public String Description { get; set; }  
}     
class QueryExpression
{
Customer[] customers = new Customer[] 
{           
new Customer 
Name = "Bill", City = "Redmond",               
Orders = new Order[] 
{                   
new Order { OrderId = 1, Amount = 100, Description = "Order 1" },                   
new Order { OrderId = 2, Amount = 200, Description = "Order 2" },                   
new Order { OrderId = 3, Amount = 300, Description = "Order 3" },               
}
},  
new Customer 
Name = "Larry", City = "Mountain View",               
Orders = new Order[] 
{                   
new Order { OrderId = 4, Amount = 400, Description = "Order 4" },                   
new Order { OrderId = 5, Amount = 500, Description = "Order 5" },               
}
}
};
public void Print() 
{
var ordersQuery = from c in customers          
from o in c.Orders           
select new { c.Name, o.OrderId, o.Amount };    
      
Console.WriteLine("Query expression join");
foreach (var v in ordersQuery) 
{           
Console.WriteLine(v);       
}  
Console.WriteLine();
// Where Clause
// A query expression with a where clause
var ordersQueryWhere = from c in customers       
from o in c.Orders       
where o.Amount > 300      
select new { c.Name, o.OrderId, o.Amount };
Console.WriteLine("Query expression join where");
foreach (var v in ordersQueryWhere) 
{           
Console.WriteLine(v);       
}  
Console.WriteLine();
}
}
class GroupClause
{
// Group and Into Clauses
// A query expression to group developers by programming language
Developer[] developers = new Developer[] 
{      
new Developer { Name = "Bill", Language = "C#" },       
new Developer { Name = "Larry", Language = "Kotlin" },       
new Developer { Name = "Tim", Language = "Swift" },  
new Developer { Name = "Anders", Language = "C#" },  
new Developer { Name = "Sergey", Language = "Kotlin" }, 
};     
public void Print() 
{
var developersGroupedByLanguage = from d in developers
group d by d.Language;
Console.WriteLine("Query expression group by");
foreach (var group in developersGroupedByLanguage) 
{      
Console.WriteLine("Language:{0}", group.Key);      
foreach (var v in group) 
{          
Console.WriteLine("{0}", v.Name);       
}  
}
Console.WriteLine();
}
}
class GroupClauseByNew
{
// A query expression to group developers by programming language and year
Developer[] developers = new Developer[] 
{      
new Developer { Name = "Bill", Language = "C#", Year = 2000 },       
new Developer { Name = "Larry", Language = "Kotlin", Year = 2011},       
new Developer { Name = "Tim", Language = "Swift", Year = 2014  },  
new Developer { Name = "Anders", Language = "C#", Year = 2000 },
new Developer { Name = "Sergey", Language = "Kotlin", Year = 2011},
};  
public void Print() 
{
var developersGroupedByLanguage = from d in developers       
group d by new { d.Language, YearCluster = (d.Year / 10) * 10 };
Console.WriteLine("Query expression group by and");
foreach (var group in developersGroupedByLanguage) 
{       
Console.WriteLine("Language:{0}", group.Key);       
foreach (var v in group) 
{           
Console.WriteLine("{0}", v.Name);       
}  
}
Console.WriteLine();
// A query expression using the into clause
var developersGroupedByLanguageInto = from d in developers       
group  d by d.Language into developersGrouped       
select new { Language = developersGrouped.Key, DevelopersCount = developersGrouped.Count() };     
Console.WriteLine("Query expression group into");
foreach (var group in developersGroupedByLanguageInto) 
{       
Console.WriteLine("Language: {0} - Number of developers: {1}", group.Language, group.DevelopersCount);
}
Console.WriteLine();
}
}
class OrderbyClause
{
Customer[] customers = new Customer[] 
{           
new Customer 
Name = "Anders", City = "Redmond",               
Orders = new Order[] 
{                   
new Order { OrderId = 1, Amount = 400, Description = "Order 1" },                   
new Order { OrderId = 2, Amount = 300, Description = "Order 2" },                   
new Order { OrderId = 3, Amount = 200, Description = "Order 3" },               
}
},  
new Customer 
Name = "Sergey", City = "Mountain View",               
Orders = new Order[] 
{                   
new Order { OrderId = 4, Amount = 500, Description = "Order 4" },                   
new Order { OrderId = 5, Amount = 100, Description = "Order 5" },               
}
}
};
public void Print() 
{
// Orderby Clause
// A query expression with an orderby clause
var ordersSortedByAmount = from c in customers       
from o in c.Orders       
orderby o.Amount      
select new { c.Name, o.OrderId, o.Amount };
Console.WriteLine("Orderby clause");
foreach (var v in ordersSortedByAmount) 
{           
Console.WriteLine(v);       
}  
Console.WriteLine();
// The following shows a query that selects orders sorted by customer Name and Amount in descending order.
var ordersSortedByCustomerAndAmount = from c in customers       
from o in c.Orders       
orderby c.Name, o.Amount descending     
select new { c.Name, o.OrderId, o.Amount };
Console.WriteLine("Orderby clause and descending");
foreach (var v in ordersSortedByCustomerAndAmount) 
{           
Console.WriteLine(v);       
}  
Console.WriteLine();
}
}
// Join Clause
class Category 
{      
public int CategoryId { get; set; }       
public String Name { get; set; }
public int Year{ get; set; }
}     
class Product 
{       
public String ProductId { get; set; }       
public int CategoryId { get; set; }       
public String Description { get; set; } 
public int Year{ get; set; }
}      
class JoinClause
Category[] categories = new Category[] 
{       
new Category { CategoryId = 1, Name = "Computer", Year = 2019},       
new Category { CategoryId = 2, Name = "Phone", Year = 2019},       
new Category { CategoryId = 3, Name = "Game Console", Year = 2020},  
};     
Product[] products = new Product[] 
{       
new Product { ProductId = "Computer01", CategoryId = 1, Description = "Surface Pro", Year = 2019},       
new Product { ProductId = "Computer02", CategoryId = 1, Description = "Macbook Pro", Year = 2019},       
new Product { ProductId = "Computer03", CategoryId = 1, Description = "Chromebook", Year = 2020},       
new Product { ProductId = "Phone01", CategoryId = 2, Description = "Pixel", Year = 2020},       
new Product { ProductId = "Phone02", CategoryId = 2, Description = "iPhone", Year = 2019},  
};     
public void Print() 
{
var categoriesAndProducts = from c in categories
join p in products on c.CategoryId equals p.CategoryId
select new { c.CategoryId, CategoryName = c.Name, Product = p.Description };     
Console.WriteLine("Join clause");
foreach (var item in categoriesAndProducts) 
{       
Console.WriteLine(item);  
}
Console.WriteLine();
// A query expression with a group join
var categoriesAndProductsInto = from c in categories       
join p in products on c.CategoryId equals p.CategoryId          
into productsByCategory       
select new { c.CategoryId, CategoryName = c.Name, Products = productsByCategory };     
Console.WriteLine("Join clause into");
foreach (var category in categoriesAndProductsInto) 
{
// Note that this time the "3 - Game Console" category is present in the output, even though it is empty
Console.WriteLine("{0} - {1}", category.CategoryId, category.CategoryName);       
foreach (var product in category.Products) 
{           
Console.WriteLine("{0}", product.Description);       
}  
}
Console.WriteLine();
// A query expression with a left outer join
var categoriesAndProductsLeftOuter = from c in categories
join p in products on c.CategoryId equals p.CategoryId          
into productsByCategory       
from pc in productsByCategory.DefaultIfEmpty( new Product { ProductId = String.Empty, Description = String.Empty, CategoryId = 0} )
select new { c.CategoryId, CategoryName = c.Name, Product = pc.Description };  
  
Console.WriteLine("Join clause left outer join");
foreach (var v in categoriesAndProductsLeftOuter) 
// Note that the "Game Console" category is present with an empty product, which is provided by the DefaultIfEmpty extension method      
Console.WriteLine(v);
}
Console.WriteLine();
// One last point to emphasize about the join clause is that you can compare elements by using composite keys.
// You simply make use of anonymous types as shown with the group keyword.
// For example, if you had a composite key in Category made up of CategoryId and Year, you could write the following statement with an anonymous type used in the equals condition:
var categoriesAndProductsLeftOuterComposite = from c in categories
join p in products on new { c.CategoryId, c.Year } equals new { p.CategoryId, p.Year }      
into productsByCategory
from pc in productsByCategory.DefaultIfEmpty( new Product { ProductId = String.Empty, Description = String.Empty, CategoryId = 0} )
select new { c.CategoryId, CategoryName = c.Name, CategoryYear = c.Year, Product = pc.Description };
Console.WriteLine("Join clause equals");
foreach (var v in categoriesAndProductsLeftOuterComposite) 
// Note that the "Game Console" category is present with CategoryYear and an empty product, which is provided by the DefaultIfEmpty extension method      
Console.WriteLine(v);
}
Console.WriteLine();
// Let Clause
// A C# sample of usage of the let clause
var categoriesByProductsNumberQuery = from c in categories
join p in products on c.CategoryId equals p.CategoryId
into productsByCategory
let ProductsCount = productsByCategory.Count()
orderby ProductsCount
select  new { c.CategoryId, ProductsCount};
Console.WriteLine("Let Clause");
foreach (var v in categoriesByProductsNumberQuery) 
{       
Console.WriteLine(v);  
}
Console.WriteLine();
}
}
class DeferredQueryEvaluation
{
// Deferred Query Evaluation and Extension Method Resolution
// Deferred Query Evaluation A query expression is not evaluated when it is defined, but only when it is used.
// Consider the following example.
// A sample LINQ query over a set of developers
List<Developer> developers = new List<Developer>(new Developer[] 
{      
new Developer { Name = "Bill", Language = "C#", Year = 2000 },       
new Developer { Name = "Larry", Language = "Kotlin", Year = 2011},       
new Developer { Name = "Tim", Language = "Swift", Year = 2014  }, 
new Developer { Name = "Anders", Language = "C#", Year = 2000 },
new Developer { Name = "Sergey", Language = "Kotlin", Year = 2011},
});     
public void Print() 
{
var query = from d in developers       
where d.Language == "C#"       
select new { d.Name, d.Year };     
Console.WriteLine("Deferred Query Evaluation");
Console.WriteLine("There are {0} C# developers.", query.Count());
// This code declares a very simple query that contains just two items, as you can see by reading the code that declares the list of developers or simply by checking the console output of the code that invokes the Count extension method:
// There are 2 C# developers.
// Now imagine that you want to change the content of the source sequence by adding a new Developer instance—after the query variable has been defined (as shown in the example).
// Sample code to modify the set of developers that are being queried
developers.Add(new Developer { Name = "Herbert", Language = "C#", Year = 2002 });     
Console.WriteLine("There are {0} C# developers.", query.Count());
// If you enumerate the query variable again or check its item count, as we do in the sample code after a new developer is added, the result is three.
// The added developer is included in the result even though he was added after the definition of query.
// The reason for this behavior is that, from a logical point of view, a query expression describes a kind of "query plan."
// It is not actually executed until it is used, and it will be executed again and again every time you run it.
// Some LINQ implementations such as LINQ to Objects implement this behavior through delegates.
// Others such as LINQ to SQL might use expression trees that take advantage of the IQueryable<T> interface.
// This behavior is known as deferred query evaluation and it is a fundamental concept in LINQ, regardless of which LINQ implementation you are using.
// Deferred query evaluation is useful because you can define queries once and apply them several times:
// If the source sequence has been changed, the result will always reflect the most recent content.
// However, consider a situation in which you want a snapshot of the result at a particular "safe point" that you want to re-use many times, avoiding re-execution, either for performance reasons or to keep the snapshot independent of changes to the source sequence.
// To do that, you need to make a copy of the result, which you can do by using a set of operators called conversion operators (such as ToArray, ToList, ToDictionary, ToLookup), created specifically for this purpose.
Console.WriteLine();
}
}
// Extension Method Resolution
// Consider the code in the following sample, which defines a custom list of type Developer (named Developers) and a class, DevelopersExtension, that provides an extension method named Where that applies specifically to instances of the Developers type
// Sample code to modify the set of developers that are being queried
sealed class Developers : List<Developer> 
{      
public Developers(IEnumerable<Developer> items) : base(items) { }  
}     
static class DevelopersExtension 
{       
public static IEnumerable<Developer> Where(this Developers source, Func<Developer, bool> predicate) 
{              
Console.WriteLine("Invoked Where extension method for Developers");           
return (source.AsEnumerable().Where(predicate));       
}          
public static IEnumerable<Developer> Where(this Developers source, Func<Developer, int, bool> predicate) 
{
Console.WriteLine("Invoked Where extension method for Developers");          
return (source.AsEnumerable().Where(predicate));       
}  
}
class ExtensionMethodResolution
{
// The only special action the custom Where extension methods take is to write some output to the console, indicating that they have executed.
// After that, the methods pass the request to the Where extension methods defined for any standard instance of type IEnumerable<T>, converting the source with a method called AsEnumerable.
// Now, if you use the usual developers array, the behavior of the query in the following sample is quite interesting.
// A query expression over a custom list of type Developers
Developers developers = new Developers(new Developer[] 
{
     new Developer { Name = "Bill", Language = "C#", Year = 2000 },       
new Developer { Name = "Larry", Language = "Kotlin", Year = 2011 },       
new Developer { Name = "Tim", Language = "Swift", Year = 2014  },
new Developer { Name = "Anders", Language = "C#", Year = 2000 },
new Developer { Name = "Sergey", Language = "Kotlin", Year = 2011},
});     
public void Print() 
{
var query = from d in developers
where d.Language == "C#"
select d;     
Console.WriteLine("Extension Method Resolution");
Console.WriteLine("There are {0} C# developers.", query.Count());
Console.WriteLine();
// The query expression will be converted by the compiler into the following code:
/*
var query = developers
.Where(d => d.Language == "C#")     
.Select(d => d);
*/
// As a result of the presence of the DevelopersExtension class, the extension method Where that executes is the one defined by DevelopersExtension, rather than the general-purpose one defined in System.Linq.Enumerable.
// (To be considered as an extension method container class, the DevelopersExtension class must be declared as static and defined in the current namespace or in any namespace included in active using directives.)
// The resulting code produced by the compiler resolving extension methods is the following:
// var query = Enumerable.Select(DevelopersExtension.Where( developers, d => d.Language == "C#"), d => d );
// In the end, you are always calling static methods of a static class, but the syntax required is lighter and more intuitive with extension methods than with the more verbose static method explicit calls.
}
}
// Degenerate Query Expressions
// Sometimes you need to iterate over the elements of a data source without any filtering, ordering, grouping, or custom projection.
// A degenerate query expression over a list of type Developers (Iteration 1)
class DegenerateQueryExpressions
{
Developers developers = new Developers(new Developer[] 
{
     new Developer { Name = "Bill", Language = "C#", Year = 2000 },       
new Developer { Name = "Larry", Language = "Kotlin", Year = 2011 },       
new Developer { Name = "Tim", Language = "Swift", Year = 2014  },
new Developer { Name = "Anders", Language = "C#", Year = 2000 },
new Developer { Name = "Sergey", Language = "Kotlin", Year = 2011},
});    
public void Print() 
{
var query = from d in developers       
select d;
foreach (var developer in query) 
{       
Console.WriteLine(developer.Name);  
}
// This code excerpt simply iterates over the data source, so you might wonder why the code does not simply use the data source directly, as in the following sample.
// Iteration over a list of type Developers (Iteration 2)
Developer[] developers2 = new Developer[] 
{      
new Developer { Name = "Bill", Language = "C#", Year = 2000 },       
new Developer { Name = "Larry", Language = "Kotlin", Year = 2011},       
new Developer { Name = "Tim", Language = "Swift", Year = 2014  },  
new Developer { Name = "Anders", Language = "C#", Year = 2000 },
new Developer { Name = "Sergey", Language = "Kotlin", Year = 2011},
};      
foreach (var developer in developers2) 
{       
Console.WriteLine(developer.Name);  
}
// Apparently, the results of both Iteration 1 and Iteration 2 are the same.
// However, using the query expression Iteration 1 ensures that if a specific Select extension method for the data source exists, the custom method will be called and the result will be consistent as a result of the translation of the query expression into its corresponding method syntax.
// A query that simply returns a result equal to the original data source (thus appearing trivial or useless) is called a degenerate query expression.
// On the other hand, iterating directly over the data source (as in Iteration 2) skips the invocation of any custom Select extension method and does not guarantee the correct behavior (unless, of course, you explicitly want to iterate over the data source without using LINQ).
}
}
// Exception Handling
class ExceptionHandling
{
// A query expression that references an external method that throws a fictitious exception
private bool DoSomething(Developer dev) 
{      
if (dev.Year == 2002)           
{
throw new ArgumentOutOfRangeException("dev");
}
     return (dev.Language == "C#");  
}     
Developer[] developers = new Developer[] 
{      
new Developer { Name = "Bill", Language = "C#", Year = 2000 },       
new Developer { Name = "Larry", Language = "Kotlin", Year = 2011},       
new Developer { Name = "Tim", Language = "Swift", Year = 2014  },  
new Developer { Name = "Anders", Language = "C#", Year = 2000 },
new Developer { Name = "Sergey", Language = "Kotlin", Year = 2011},
new Developer { Name = "Herbert", Language = "C#", Year = 2002 },
};
public void Print() 
{       
var query = from d in developers
let SomethingResult = DoSomething(d)         
select new { d.Name, SomethingResult };
/*
foreach (var v in query) 
{           
Console.WriteLine(v);       
}  
*/
// The DoSomething method throws a fictitious exception for any developer older than 40.
// We call this method from inside the query.
// During query execution, when the query iterates over the developer Tim and year 2014, the custom method will throw an exception.
// First, you should think carefully about calling custom methods in query definitions, because it is a potentially dangerous habit, as you can see when executing this sample code.
// However, in cases in which you do decide to call external methods, the best way to work with them is to wrap the enumeration of the query result with a try … catch block.
// In fact, as seen in "Deferred Query Evaluation," a query expression is executed each time it is enumerated, and not when it is defined.
// Thus, the correct way of writing the code in Listing 2-28 is presented in the following sample.
// A query expression used with exception handling
try 
{       
foreach (var v in query) 
{           
Console.WriteLine(v);       
}  
catch (ArgumentOutOfRangeException e) 
{       
Console.WriteLine(e.Message);  
}
}
}
// In general, it is useless to wrap a query expression definition with a try catch block.
// Moreover, for the same reason, you should avoid using the results of methods or constructors directly as data sources for a query expression and should instead assign their results to instance variables, wrapping the variable assignment with a try catch block as in the following sample:
// A query expression with exception handling in a local variables declaration
class ExceptionHandledInDataSource
{
Developer[] developers = null;
private bool DoSomething(Developer dev) 
{
if (dev.Year == 2002)
{
return (dev.Language == "C#");
}
return true;
}
public void Print() 
{
try
{          
developers = createDevelopersDataSource();       
}       
catch (InvalidOperationException e) 
{           
// Imagine that the createDevelopersDataSource           
// throws an InvalidOperationException in case of failure              
// Handle it somehow ...
Console.WriteLine(e.Message);       
}         
if (developers != null)       
{           
var query = from d in developers
let SomethingResult = DoSomething(d)               
select new { d.Name, SomethingResult };              
try 
{               
foreach (var item in query) 
{                   
Console.WriteLine(item);               
}           
}           
catch (ArgumentOutOfRangeException e) 
{               
Console.WriteLine(e.Message);           
}       
}
}
private Developer[] createDevelopersDataSource()
{       
// Fictitious InvalidOperationException thrown       
throw new InvalidOperationException();  
}
}
class Program
{       
static void Main() 
Query qry = new Query();
qry.Print();
WhereClause where = new WhereClause();
where.Print();
FromClause from = new FromClause();
from.Print();
QueryExpression query = new QueryExpression();
query.Print();
GroupClause group = new GroupClause();
group.Print();
GroupClauseByNew groupByNew = new GroupClauseByNew();
groupByNew.Print();
OrderbyClause orderby = new OrderbyClause();
orderby.Print();
JoinClause join = new JoinClause();
join.Print();
DeferredQueryEvaluation deferQueryEvaluation = new DeferredQueryEvaluation();
deferQueryEvaluation.Print();
ExtensionMethodResolution extMethodResolution = new ExtensionMethodResolution();
extMethodResolution.Print();
ExceptionHandling exHandling = new ExceptionHandling();
exHandling.Print();
ExceptionHandledInDataSource exHandledInDataSource = new ExceptionHandledInDataSource();
exHandledInDataSource.Print();
}
}
/*
Courtesies:
C# The Complete Reference by Herbert Schildt
https://docs.microsoft.com
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment