.NET Technical bits: April 2010

Tuesday, April 20, 2010

Structs in C#

• Within a struct declaration, fields cannot be initialized unless they are declared as const or static.
• A struct may not declare a default constructor (a constructor without parameters) or a destructor.
• Structs are copied on assignment. When a struct is assigned to a new variable, all the data is copied, and any modification to the new copy does not change the data for the original copy. This is important to remember when working with collections of value types such as Dictionary.
• Structs are value types and classes are reference types.
• Unlike classes, structs can be instantiated without using a new operator.
• Structs can declare constructors that have parameters.
• A struct cannot inherit from another struct or class, and it cannot be the base of a class. All structs inherit directly from System.ValueType, which inherits from System.Object.
• A struct can implement interfaces.
• A struct can be used as a nullable type and can be assigned a null value.

Wednesday, April 7, 2010

Joins in LINQ Query Expressions

As we discussed in the prevoius post a join clause takes two source sequences as input. The elements in each sequence must either be or contain a property that can be compared to a corresponding property in the other sequence. The join clause compares the specified keys for equality by using the special equals keyword. All joins performed by the join clause are equijoins. The shape of the output of a join clause depends on the specific type of join you are performing. The following are three most common join types:

1. Inner join

The following example shows a simple inner equijoin. This query produces a flat sequence of “product name / category” pairs. The same category string will appear in multiple elements. If an element from categories has no matching products, that category will not appear in the results.

var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name }; //produces flat sequence


2. Group join

A join clause with an into expression is called a group join.

var innerGroupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new { CategoryName = category.Name, Products = prodGroup };


A group join produces a hierarchical result sequence, which associates elements in the left source sequence with one or more matching elements in the right side source sequence. A group join has no equivalent in relational terms; it is essentially a sequence of object arrays.

If no elements from the right source sequence are found to match an element in the left source, the join clause will produce an empty array for that item. Therefore, the group join is still basically an inner-equijoin except that the result sequence is organized into groups.

If you just select the results of a group join, you can access the items, but you cannot identify the key that they match on. Therefore, it is generally more useful to select the results of the group join into a new type that also has the key name, as shown in the previous example.

You can also, of course, use the result of a group join as the generator of another subquery:

var innerGroupJoinQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from prod2 in prodGroup
where prod2.UnitPrice > 2.50M
select prod2;


3. Left outer join

In a left outer join, all the elements in the left source sequence are returned, even if no matching elements are in the right sequence. To perform a left outer join in LINQ, use the DefaultIfEmpty method in combination with a group join to specify a default right-side element to produce if a left-side element has no matches. You can use null as the default value for any reference type, or you can specify a user-defined default type. In the following example, a user-defined default type is shown:

var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product{Name = String.Empty, CategoryID = 0})
select new { CatName = category.Name, ProdName = item.Name };


from: A query expression must begin with a from clause. Additionally, a query expression can contain sub-queries, which also begin with a from clause. The from clause specifies the following:

o The data source on which the query or sub-query will be run.
o A local range variable that represents each element in the source sequence.
Both the range variable and the data source are strongly typed. The data source referenced in the from clause must have a type of IEnumerable, IEnumerable<(Of <(T>)>), or a derived type such as IQueryable<(Of <(T>)>).

let: In a query expression, it is sometimes useful to store the result of a sub-expression in order to use it in subsequent clauses. You can do this with the let keyword, which creates a new range variable and initializes it with the result of the expression you supply. Once initialized with a value, the range variable cannot be used to store another value. However, if the range variable holds a queryable type, it can be queried.

In the following example let is used in two ways:
o To create an enumerable type that can itself be queried.
o To enable the query to call ToLower only one time on the range variable word. Without using let, you would have to call ToLower in each predicate in the where clause.

class LetSample1
{
static void Main()
{
string[] strings =
{
"A penny saved is a penny earned.",
"The early bird catches the worm.",
"The pen is mightier than the sword."
};

// Split the sentence into an array of words
// and select those whose first letter is a vowel.
var earlyBirdQuery =
from sentence in strings
let words = sentence.Split(' ')
from word in words
let w = word.ToLower()
where w[0] == 'a' || w[0] == 'e'
|| w[0] == 'i' || w[0] == 'o'
|| w[0] == 'u'
select word;

// Execute the query.
foreach (var v in earlyBirdQuery)
{
Console.WriteLine("\"{0}\" starts with a vowel", v);
}

// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
"A" starts with a vowel
"is" starts with a vowel
"a" starts with a vowel
"earned." starts with a vowel
"early" starts with a vowel
"is" starts with a vowel
*/

Details on LINQ Query Expressions

A query expression is a query expressed in query syntax. A query expression is a first-class language construct. It is just like any other expression and can be used in any context in which a C# expression is valid. A query expression consists of a set of clauses written in a declarative syntax similar to SQL or XQuery. Each clause in turn contains one or more C# expressions, and these expressions may themselves be either a query expression or contain a query expression.

A query expression must begin with a from clause and must end with a select or group clause. Between the first from clause and the last select or group clause, it can contain one or more of these optional clauses: where, orderby, join, let and even additional from clauses. You can also use the into keyword to enable the result of a join or group clause to serve as the source for additional query clauses in the same query expression.

• The Query Variable :

In LINQ, a query variable is any variable that stores a query instead of the results of a query. More specifically, a query variable is always an enumerable type that will produce a sequence of elements when it is iterated over in a foreach statement or a direct call to its IEnumerator.MoveNext method.
The following code example shows a simple query expression with one data source, one filtering clause, one ordering clause, and no transformation of the source elements. The select clause ends the query.

static void Main()
{
// Data source.
int[] scores = { 90, 71, 82, 93, 75, 82 };

// Query Expression.
IEnumerable scoreQuery = //query variable
from score in scores //required
where score > 80 // optional
orderby score descending // optional
select score; //must end with select or group

// Execute the query to produce the results
foreach (int testScore in scoreQuery)
{
Console.WriteLine(testScore);
}
}
// Outputs: 90 82 93 82


In the previous example, scoreQuery is a query variable, which is sometimes referred to as just a query. The query variable stores no actual result data, which is produced in the foreach loop. And when the foreach statement executes, the query results are not returned through the query variable scoreQuery. Rather, they are returned through the iteration variable testScore. The scoreQuery variable can be iterated in a second foreach loop. It will produce the same results as long as neither it nor the data source has been modified.

A query variable may store a query that is expressed in query syntax or method syntax, or a combination of the two. In the following examples, both queryMajorCities and queryMajorCities2 are query variables:


//Query syntax
IEnumerable queryMajorCities =
from city in cities
where city.Population > 100000
select city;

// Method-based syntax
IEnumerable queryMajorCities2 = cities.Where(c => c.Population > 100000);


• Starting a query expression:

A query expression must begin with a from clause. It specifies a data source together with a range variable. The range variable represents each successive element in the source sequence as the source sequence is being traversed. The range variable is strongly typed based on the type of elements in the data source. In the following example, because countries is an array of Country objects, the range variable is also typed as Country. Because the range variable is strongly typed, you can use the dot operator to access any available members of the type.

A query expression may contain multiple from clauses. Use additional from clauses when each element in the source sequence is itself a collection or contains a collection. For example, assume that you have a collection of Country objects, each of which contains a collection of City objects named Cities. To query the City objects in each Country, use two from clauses as shown here:

IEnumerable cityQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;


• Ending a Query Expression:

A query expression must end with either a select clause or a group clause.
select: In a query expression, the select clause specifies the type of values that will be produced when the query is executed. The result is based on the evaluation of all the previous clauses and on any expressions in the select clause itself. A query expression must terminate with either a select clause or a group clause.

class SelectSample1
{
static void Main()
{
//Create the data source
List Scores = new List() { 97, 92, 81, 60 };

// Create the query.
IEnumerable queryHighScores =
from score in Scores
where score > 80
select score;

// Execute the query.
foreach (int i in queryHighScores)
{
Console.Write(i + " ");
}
}
}


group: The group clause returns a sequence of IGrouping<(Of <(TKey, TElement>)>) objects that contain zero or more items that match the key value for the group. For example, you can group a sequence of strings according to the first letter in each string. In this case, the first letter is the key and has a type char, and is stored in the Key property of each IGrouping<(Of <(TKey, TElement>)>) object. The compiler infers the type of the key.


// Query variable is an IEnumerable<igrouping<char,>>
var studentQuery1 =
from student in students
group student by student.Last[0];


• Filtering, Ordering, and Joining:

Between the starting from clause, and the ending select or group clause, all other clauses (where, join, orderby, from, let) are optional. Any of the optional clauses may be used zero times or multiple times in a query body.

where: The where clause is used in a query expression to specify which elements from the data source will be returned in the query expression. It applies a Boolean condition (predicate) to each source element (referenced by the range variable) and returns those for which the specified condition is true. A single query expression may contain multiple where clauses and a single clause may contain multiple predicate sub expressions.

orderby: In a query expression, the orderby clause causes the returned sequence or subsequence (group) to be sorted in either ascending or descending order. Multiple keys can be specified in order to perform one or more secondary sort operations. The sorting is performed by the default comparer for the type of the element. The default sort order is ascending. You can also specify a custom comparer. However, it is only available by using method-based syntax.

class OrderbySample1
{
static void Main()
{
// Create a delicious data source.
string[] fruits = { "cherry", "apple", "blueberry" };

// Query for ascending sort.
IEnumerable sortAscendingQuery =
from fruit in fruits
orderby fruit //"ascending" is default
select fruit;

// Query for descending sort.
IEnumerable sortDescendingQuery =
from w in fruits
orderby w descending
select w;

// Execute the query.
Console.WriteLine("Ascending:");
foreach (string s in sortAscendingQuery)
{
Console.WriteLine(s);
}

// Execute the query.
Console.WriteLine(Environment.NewLine + "Descending:");
foreach (string s in sortDescendingQuery)
{
Console.WriteLine(s);
}

// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Ascending:
apple
blueberry
cherry

Descending:
cherry
blueberry
apple
*/


join: A join clause takes two source sequences as input. The elements in each sequence must either be or contain a property that can be compared to a corresponding property in the other sequence. The join clause compares the specified keys for equality by using the special equals keyword. All joins performed by the join clause are equijoins. The shape of the output of a join clause depends on the specific type of join you are performing.

• Continuations with "into":

The into contextual keyword can be used to create a temporary identifier to store the results of a group, join or select clause into a new identifier. This identifier can itself be a generator for additional query commands. When used in a group or select clause, the use of the new identifier is sometimes referred to as a continuation.

• Subqueries in a Query Expression:

A query clause may itself contain a query expression, which is sometimes referred to as a subquery. Each subquery starts with its own from clause that does not necessarily point to the same data source in the first from clause. For example, the following query shows a query expression that is used in the select statement to retrieve the results of a grouping operation.

var queryGroupMax =
from student in students
group student by student.GradeLevel into studentGroup
select new
{
Level = studentGroup.Key,
HighestScore =
(from student2 in studentGroup
select student2.Scores.Average())
.Max()
};

Overview of LINQ Query Expressions

Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language (also in Visual Basic and potentially any other .NET language). With LINQ, a query is now a first-class language construct, just like classes, methods, events and so on.

For a developer who writes queries, the most visible "language-integrated" part of LINQ is the query expression. Query expressions are written in a declarative query syntax introduced in C# 3.0. By using query syntax, you can perform even complex filtering, ordering, and grouping operations on data sources with a minimum of code. You use the same basic query expression patterns to query and transform data in SQL databases, ADO.NET Datasets, XML documents and streams, and .NET collections.

The following are the overview of Query Expressions:

• Query expressions can be used to query and to transform data from any LINQ-enabled data source. For example, a single query can retrieve data from a SQL database, and produce an XML stream as output.
• Query expressions are easy to master because they use many familiar C# language constructs.
• The variables in a query expression are all strongly typed, although in many cases you do not have to provide the type explicitly because the compiler can infer it.
• A query is not executed until you iterate over the query variable in a foreach statement.
• At compile time, query expressions are converted to Standard Query Operator method calls according to the rules set forth in the C# specification. Any query that can be expressed by using query syntax can also be expressed by using method syntax. However, in most cases query syntax is more readable and concise.
• As a rule when you write LINQ queries, we recommend that you use query syntax whenever possible and method syntax whenever necessary. There is no semantic or performance difference between the two different forms. Query expressions are often more readable than equivalent expressions written in method syntax.
• Some query operations, such as Count or Max, have no equivalent query expression clause and must therefore be expressed as a method call. Method syntax can be combined with query syntax in various ways.
• Query expressions can be compiled to expression trees or to delegates, depending on the type that the query is applied to. IEnumerable<(Of <(T>)>) queries are compiled to delegates. IQueryable and IQueryable<(Of <(T>)>) queries are compiled to expression trees.

Microsoft Enterprise Library

The Microsoft Enterprise Library is a collection of reusable software components (application blocks) designed to assist software developers with common enterprise development cross-cutting concerns (such as logging, validation, data access, exception handling, and many others). Application blocks are a type of guidance; they are provided as source code, test cases, and documentation that can be used "as is," extended, or modified by developers to use on complex, enterprise-level line-of-business development projects.

Active Releases

• Enterprise Library 4.1 - October 2008
• Enterprise Library 4.0 - May 2008
• Enterprise Library 3.1 - May 2007
• Enterprise Library 2.0 - January 2006

Benefits of Enterprise Library

The design of application blocks encapsulates the Microsoft recommended and proven practices for .NET application development. These good practices are demonstrated in the overall design of the Enterprise Library, as well in the context-specific guidelines in the design of individual application blocks and QuickStarts. Software developers can add application blocks to .NET applications quickly and easily. For example, the Data Access Application Block provides access to the most frequently used features of ADO.NET, exposing them through easily used classes. In some cases, application blocks also add related functionality not directly supported by the underlying class libraries.

Goals for Enterprise Library

Enterprise Library is a collection of application blocks intended for use by developers who build complex, enterprise-level applications.
Enterprise Library is used when building applications that are typically to be deployed widely and to interoperate with other applications and systems. In addition, they generally have strict security, reliability, and performance requirements.
The goals of Enterprise Library are the following:
Consistency. All Enterprise Library application blocks feature consistent design patterns and implementation approaches.
Extensibility. All application blocks include defined extensibility points that allow developers to customize the behavior of the application blocks by adding their own code.
Ease of use. Enterprise Library offers numerous usability improvements, including a graphical configuration tool, a simpler installation procedure, and clearer and more complete documentation and samples.

Tuesday, April 6, 2010

Model View Controller

Model View Controller is a design approach to separate the application object model from GUI, originally invented around 80s. Then later on it has become a widely accepted common design pattern. The main objective behind this pattern is to decouple the view of the data (presentation layer) from the actual data processing so that the same model can be used for various views. This is achieved by using three different types of objects that interact with each other in loosely coupled manner with their discreet set of tasks.
These three objects are known as Model, View and Controller. We will learn for each of them here.

VIEW:

View is the graphical data presentation (outputting) irrespective of the real data processing. View is the responsible for look and feel, some custom formatting, sorting etc. View is completely isolated from actual complex data operations. For example, Online product catalog view is completely separated from database connection, query, tables etc. It simply gets final row-data from the model and puts some cosmetics and formatting before displaying it in browser. View provides interface to interact with the system. The beauty of MVC approach is that it supports any kind of view, which is challenging in todays distributed and multi-platform environment.

A MVC model can have multiple views, which are controlled by controller. View interface can be of WEB-FORMS, HTML, XML/XSLT, XTML, and WML or can be Windows forms etc.

MODEL:

Model is responsible for actual data processing, like database connection, querying database, implementing business rules etc. It feeds data to the view without worrying about the actual formatting and look and feel. Data provided by Model is display-neutral so it can be interfaced with as many views without code redundancy; this eases your code maintenance and reduces bugs and allows code -reuse at good extent. Model responds to the request made by controllers and notifies the registered views to update their display with new data.

CONTROLLER:

Controller is responsible for Notice of action. Controller responds to the mouse or keyboard input to command model and view to change. Controllers are associated with views. User interaction triggers the events to change the model, which in turn calls some methods of model to update its state to notify other registered views to refresh their display.

Benefits:

Following are the few of the benefits of MVC design pattern.
• Since MVC handles the multiple views using the same enterprise model it is easier to maintain, test and upgrade the multiple system.
• It will be easier to add new clients just by adding their views and controllers.
• Since the Model is completely decoupled from view it allows lot of flexibilities to design and implement the model considering reusability and modularity. This model also can be extended for further distributed application.
• It is possible to have development process in parallel for model, view and controller.
• This makes the application extensible and scalable.

Drawbacks:

• Requires high skilled experienced professionals who can identify the requirements in depth at the front before actual design.
• It requires the significant amount of time to analyze and design.
• This design approach is not suitable for smaller applications. It Overkills the small applications.

Design Patterns

What is a Design Pattern?

Design Pattern is a re-usable, high quality solution to a given requirement, task or recurring problem. Further, it does not comprise of a complete solution that may be instantly converted to a code component, rather it provides a framework for how to solve a problem.

In 1994, the release of the book Design Patterns, Elements of Reusable Object Oriented Software made design patterns popular.

Because design patterns consist of proven reusable architectural concepts, they are reliable and they speed up software development process.

Design Patterns are in a continuous phase of evolution, which means that they keep on getting better & better as they are tested against time, reliability and subjected to continuous improvements. Further, design patterns have evolved towards targeting specific domains. For example, windows-based banking applications are usually based on singleton patterns, e-commerce web applications are based on the MVC (Model-View-Controller) pattern.

Design Patterns are categorized into 3 types:

1) Creational Patterns

The Creational Design Patterns focus on how objects are created and utilized in an application. They tackle the aspects of when and how objects are created, keeping in mind what is the best way these objects should be created.

Listed below are some of the commonly known Creational Design Patterns:
>>> Abstract Factory Pattern
>>> Factory Pattern
>>> Builder Pattern
>>> Lazy Pattern
>>> Prototype Pattern
>>> Singleton Pattern

2) Structural Patterns

A structural design pattern establishes a relationship between entities. Thus making it easier for different components of an application to interact with each other. Following are some of the commonly known structural patterns:
>>> Adapter Pattern
>>> Bridge Pattern
>>> Composite Pattern
>>> Decorator Pattern
>>> Facade Pattern
>>> Flyweight Pattern
>>> Proxy Pattern

3) Behavioral Patterns

Behaviorial design patterns focus on improving the communication between different objects. Following are different types of behavioral patterns:
>>> Chain Or Responsibilities Pattern
>>> Command Pattern
>>> Observer Pattern

Capability Maturity Model (CMM)

CMM is an abbreviation for Capability Maturity Model (CMM). The CMM was originally intended as a tool for objectively assessing the ability of government contractors' processes to perform a contracted software project. CMM (Capability Maturity Model) Level 5 represents the top level of certified software development process: managed, repeatable, documented, self-optimizing. It is certified by Software Engineering Institute, USA. The company will be evaluated in all aspects of Quality, Customer report, document management, HR Management etc

Maturity model

A maturity model can be described as a structured collection of elements that describe certain aspects of maturity in an organization. A maturity model may provide, for example:
• a place to start
• the benefit of a community’s prior experiences
• a common language and a shared vision
• a framework for prioritizing actions
• a way to define what improvement means for your organization.
A maturity model can be used as a benchmark for comparison and as an aid to understanding - for example, for comparative assessment of different organizations where there is something in common that can be used as a basis for comparison. In the case of the CMM, for example, the basis for comparison would be the organizations' software development processes.

Levels of the Capability Maturity Model

There are five levels defined along the continuum of the CMM, and, according to the SEI: "Predictability, effectiveness, and control of an organization's software processes are believed to improve as the organization moves up these five levels. While not rigorous, the empirical evidence to date supports this belief."

1. Initial (chaotic, ad hoc, individual heroics) - the starting point for use of a new process.
2. Managed - the process is managed according to the metrics described in the Defined stage.
3. Defined - the process is defined/confirmed as a standard business process, and decomposed to levels 0, 1 and 2 (the latter being Work Instructions).
4. Quantitatively managed
5. Optimized - process management includes deliberate process optimization/improvement.

Within each of these maturity levels are Key Process Areas (KPAs) which characterise that level, and for each KPA there are five definitions identified:

1. Goals
2. Commitment
3. Ability
4. Measurement
5. Verification

The KPAs are not necessarily unique to CMM, representing — as they do — the stages that organizations must go through on the way to becoming mature.

The CMM provides a theoretical continuum along which process maturity can be developed incrementally from one level to the next. Skipping levels is not allowed/feasible.

Level 1 - Initial (Chaotic)
It is characteristic of processes at this level that they are (typically) undocumented and in a state of dynamic change, tending to be driven in an ad hoc, uncontrolled and reactive manner by users or events. This provides a chaotic or unstable environment for the processes.

Level 2 - Repeatable

It is characteristic of processes at this level that some processes are repeatable, possibly with consistent results. Process discipline is unlikely to be rigorous, but where it exists it may help to ensure that existing processes are maintained during times of stress.

Level 3 - Defined

It is characteristic of processes at this level that there are sets of defined and documented standard processes established and subject to some degree of improvement over time. These standard processes are in place (i.e., they are the AS-IS processes) and used to establish consistency of process performance across the organization.

Level 4 - Managed
It is characteristic of processes at this level that, using process metrics, management can effectively control the AS-IS process (e.g., for software development). In particular, management can identify ways to adjust and adapt the process to particular projects without measurable losses of quality or deviations from specifications. Process Capability is established from this level.

Level 5 - Optimized
It is a characteristic of processes at this level that the focus is on continually improving process performance through both incremental and innovative technological changes/improvements.

At maturity level 5, processes are concerned with addressing statistical common causes of process variation and changing the process (for example, to shift the mean of the process performance) to improve process performance. This would be done at the same time as maintaining the likelihood of achieving the established quantitative process-improvement objectives.

Monday, April 5, 2010

Extension Methods

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C# and Visual Basic, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.


The most common extension methods are the LINQ standard query operators that add query functionality to the existing System.Collections..::.IEnumerable and System.Collections.Generic..::.IEnumerable<(Of <(T>)>) types. To use the standard query operators, first bring them into scope with a using System.Linq directive. Then any type that implements IEnumerable<(Of <(T>)>) appears to have instance methods such as GroupBy, OrderBy, Average, and so on. You can see these additional methods in IntelliSense statement completion when you type "dot" after an instance of an IEnumerable<(Of <(T>)>) type such as List<(Of <(T>)>) or Array.
The following example shows how to call the standard query operator OrderBy method on an array of integers. The expression in parentheses is a lambda expression. Many standard query operators take lambda expressions as parameters, but this is not a requirement for extension methods.


class ExtensionMethods2
{

static void Main()
{
int[] ints = { 10, 45, 15, 39, 21, 26 };
var result = ints.OrderBy(g => g);
foreach (var i in result)
{
System.Console.Write(i + " ");
}
}
}
//Output: 10 15 21 26 39 45

Extension methods are defined as static methods but are called by using instance method syntax. Their first parameter specifies which type the method operates on, and the parameter is preceded by the this modifier. Extension methods are only in scope when you explicitly import the namespace into your source code with a using directive.


The following example shows an extension method defined for the System..::.String class. Note that it is defined inside a non-nested, non-generic static class:


namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}

The WordCount extension method can be brought into scope with this using directive:


using ExtensionMethods;

And it can be called from an application by using this syntax:


string s = "Hello Extension Methods";
int i = s.WordCount();

In your code you invoke the extension method with instance method syntax. However, the intermediate language (IL) generated by the compiler translates your code into a call on the static method. Therefore, the principle of encapsulation is not really being violated. In fact, extension methods cannot access private variables in the type they are extending.

Access Specifiers in C#

Public - The type or member can be accessed by any other code in the same assembly or another assembly that references it.

Private - The type or member can only be accessed by code in the same class or struct.

Protected – The type or member can only be accessed by code in the same class or struct, or in a derived class.

Internal – The type or member can be accessed by any code in the same assembly, but not from another assembly.

Protected internal - The type or member can be accessed by any code in the same assembly, or by any derived class in another assembly. The protected internal accessibility means protected OR internal, not protected AND internal. In other words, a protected internal member is accessible from any class in the same assembly, including derived classes. To limit accessibility to only derived classes in the same assembly, declare the class itself internal, and declare its members as protected.

C# classes and class types

Classes
A class is a construct that enables you to create your own custom types by grouping together variables of other types, methods and events. A class is like a blueprint. It defines the data and behavior of a type. If the class is not declared as static, client code can use it by creating objects or instances which are assigned to a variable. The variable remains in memory until all references to it go out of scope. At that time, the CLR marks it as eligible for garbage collection. If the class is declared as static, then only one copy exists in memory and client code can only access it through the class itself, not an instance variable.

Types of classes
• Static Class
Contains only static members, Cannot be instantiated, is sealed, Cannot contain Instance Constructors (default constructor)
• Partial Class
It is possible to split the definition of a class or a struct, an interface or a method over two or more source files. Each source file contains a section of the type or method definition, and all parts are combined when the application is compiled.
The partial keyword indicates that other parts of the class, struct, or interface can be defined in the namespace. All the parts must use the partial keyword. All the parts must be available at compile time to form the final type. All the parts must have the same accessibility, such as public, private, and so on.
• Abstract Class
An abstract class cannot be instantiated. The purpose of an abstract class is to provide a common definition of a base class that multiple derived classes can share. For example, a class library may define an abstract class that is used as a parameter to many of its functions, and require programmers using that library to provide their own implementation of the class by creating a derived class.
• Sealed Class
A sealed class cannot be used as a base class. For this reason, it cannot also be an abstract class. Sealed classes prevent derivation. Because they can never be used as a base class, some run-time optimizations can make calling sealed class members slightly faster.