Saturday, March 23, 2013

Auto Generate Class from a Table in SQL Server

Here is the SQL Script which will generate a class for a table

--Begin


DECLARE @TableName VARCHAR(MAX) = 'Person'
DECLARE @TableSchema VARCHAR(MAX) = 'dbo'
DECLARE @result varchar(max) = ''

SET @result = @result + 'using System;' + CHAR(13) + CHAR(13)

IF (@TableSchema IS NOT NULL)
BEGIN
    SET @result = @result + 'namespace ' + @TableSchema  + CHAR(13) + '{' + CHAR(13)
END

SET @result = @result + 'public class ' + @TableName + CHAR(13) + '{' + CHAR(13)

SET @result = @result + '#region Instance Properties' + CHAR(13)

SELECT @result = @result + CHAR(13)
    + ' public ' + ColumnType + ' ' + ColumnName + ' { get; set; } ' + CHAR(13)
FROM
(
    SELECT  c.COLUMN_NAME   AS ColumnName
        , CASE c.DATA_TYPE  
            WHEN 'bigint' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Int64?' ELSE 'Int64' END
            WHEN 'binary' THEN 'Byte[]'
            WHEN 'bit' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Boolean?' ELSE 'Boolean' END          
            WHEN 'char' THEN 'String'
            WHEN 'date' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END                      
            WHEN 'datetime' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END                      
            WHEN 'datetime2' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END                      
            WHEN 'datetimeoffset' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'DateTimeOffset?' ELSE 'DateTimeOffset' END                                  
            WHEN 'decimal' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Decimal?' ELSE 'Decimal' END                                  
            WHEN 'float' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Single?' ELSE 'Single' END                                  
            WHEN 'image' THEN 'Byte[]'
            WHEN 'int' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Int32?' ELSE 'Int32' END
            WHEN 'money' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Decimal?' ELSE 'Decimal' END                                              
            WHEN 'nchar' THEN 'String'
            WHEN 'ntext' THEN 'String'
            WHEN 'numeric' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Decimal?' ELSE 'Decimal' END                                                          
            WHEN 'nvarchar' THEN 'String'
            WHEN 'real' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Double?' ELSE 'Double' END                                                                      
            WHEN 'smalldatetime' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END                                  
            WHEN 'smallint' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Int16?' ELSE 'Int16'END          
            WHEN 'smallmoney' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Decimal?' ELSE 'Decimal' END                                                                      
            WHEN 'text' THEN 'String'
            WHEN 'time' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'TimeSpan?' ELSE 'TimeSpan' END                                                                                  
            WHEN 'timestamp' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'DateTime?' ELSE 'DateTime' END                                  
            WHEN 'tinyint' THEN
                CASE C.IS_NULLABLE
                    WHEN 'YES' THEN 'Byte?' ELSE 'Byte' END                                              
            WHEN 'uniqueidentifier' THEN 'Guid'
            WHEN 'varbinary' THEN 'Byte[]'
            WHEN 'varchar' THEN 'String'
            ELSE 'Object'
        END AS ColumnType
        , c.ORDINAL_POSITION
FROM    INFORMATION_SCHEMA.COLUMNS c
WHERE   c.TABLE_NAME = @TableName and ISNULL(@TableSchema, c.TABLE_SCHEMA) = c.TABLE_SCHEMA
) t
ORDER BY t.ORDINAL_POSITION

SET @result = @result + CHAR(13) + '#endregion Instance Properties' + CHAR(13)

SET @result = @result  + '}' + CHAR(13)

IF (@TableSchema IS NOT NULL)
BEGIN
    SET @result = @result + CHAR(13) + '}'
END

PRINT @result




--and here is its output

using System;

namespace dbo
{
public class Person
{
#region Instance Properties

 public Int64 Id { get; set; }

 public String FirstName { get; set; }

 public String MI { get; set; }

 public String LastName { get; set; }

 public String FaceBookId { get; set; }

 public String Email { get; set; }

 public String TwitterId { get; set; }

 public String LinkedInId { get; set; }

#endregion Instance Properties
}

}



Thursday, February 28, 2013

A Sample NANT Build Script with Subversion

Here is a sample NANT script which is originally referred from  Build Script in "Expert .Net Delivery", here it uses Subversion to fetch latest code from subversion which is what is different from original script.


<?xml version="1.0" encoding="utf-8" ?>
<project name="SampleTool" default="help">
<description>Build file for the SampleTool application.</description>

<property name="nant.onfailure" value="fail"/>
<property name="svnLocation" value="c:\program files\subversion\bin\svn.exe" />

     <loadtasks assembly="D:\dotNetDelivery\Tools\NAntContrib\0.85rc2\bin\NAnt.Contrib.Tasks.dll"/>
     <loadtasks assembly="D:\dotNetDelivery\Tools\NUnit2Report\1.2.2\bin\NAnt.NUnit2ReportTasks.dll"/>
<sysinfo/>

<target name="go" description="The main target for full build process execution." depends="clean, get, version1, version2, build, test, document, publish, notify"/>

<target name="clean" description="Clean up the build environment.">
<delete dir="D:\dotNetDelivery\BuildArea\Source\" failonerror="false"/>
<delete dir="D:\dotNetDelivery\BuildArea\Output\" failonerror="false"/>
<delete dir="D:\dotNetDelivery\BuildArea\Docs\" failonerror="false"/>
<delete dir="D:\dotNetDelivery\BuildArea\Reports\" failonerror="false"/>
<delete dir="D:\dotNetDelivery\BuildArea\Distribution\" failonerror="false"/>

<mkdir dir="D:\dotNetDelivery\BuildArea\Source\"/>
<mkdir dir="D:\dotNetDelivery\BuildArea\Output\"/>
<mkdir dir="D:\dotNetDelivery\BuildArea\Docs\"/>
<mkdir dir="D:\dotNetDelivery\BuildArea\Reports\"/>
<mkdir dir="D:\dotNetDelivery\BuildArea\Distribution\"/>
<mkdir dir="D:\dotNetDelivery\BuildArea\Publish\" failonerror="false"/>

</target>

<target name="get" description="Grab the source code." >
  <exec program="${svnLocation}" commandline="checkout http://some.repository.com/trunk/src/SampleTool SampleTool --username *username* --password *somepassword*"/>
 </target>


<target name="version1" description="Apply versioning to the source code files.">

<property name="sys.version" value="0.0.0.0"/>

<ifnot test="${debug}">
<version buildtype="increment" revisiontype="increment" path="SampleTool.Build.Number"/>
</ifnot>

<attrib file="D:\dotNetDelivery\BuildArea\Source\CommonAssemblyInfo.cs" readonly="false" />

<asminfo output="D:\dotNetDelivery\BuildArea\Source\CommonAssemblyInfo.cs" language="CSharp">
<imports>
<import name="System" />
<import name="System.Reflection"/>
</imports>
<attributes>
<attribute type="AssemblyVersionAttribute" value="${sys.version}" />
<attribute type="AssemblyProductAttribute" value="SampleTool" />
<attribute type="AssemblyCopyrightAttribute" value="Copyright (c) 2005, Etomic Ltd."/>
</attributes>
</asminfo>

<attrib file="D:\dotNetDelivery\BuildArea\Source\CommonAssemblyInfo.cs" readonly="true" />
</target>

<target name="version2">
<ifnot test="${debug}">
<vsslabel
user="builder"
password="builder"
dbpath="D:\dotNetDelivery\VSS\srcsafe.ini"
path="$/Solutions/SampleTool/"
comment="Automated Label"
label="NAnt - ${sys.version}"
/>
</ifnot>
</target>

<target name="build" description="Compile the application.">
<solution solutionfile="D:\dotNetDelivery\BuildArea\Source\SampleTool.sln" configuration="Debug" outputdir="D:\dotNetDelivery\BuildArea\Output\"/>
</target>

<target name="test" description="Apply the unit tests.">
<property name="nant.onfailure" value="fail.test"/>

<nunit2>
<formatter type="Xml" usefile="true" extension=".xml" outputdir="D:\dotNetDelivery\BuildArea\Reports\" />
<test assemblyname="D:\dotNetDelivery\BuildArea\Output\SampleToolTests.dll" />
</nunit2>

<nunit2report out="D:\dotNetDelivery\BuildArea\Reports\NUnit.html">
<fileset>
<include name="D:\dotNetDelivery\BuildArea\Reports\SampleToolTests.dll-results.xml" />
</fileset>
</nunit2report>

<exec program="D:\dotNetDelivery\Tools\FxCop\1.30\FxCopCmd.exe" commandline="/f:D:\dotNetDelivery\BuildArea\Output\SampleToolEngine.dll /f:D:\dotNetDelivery\BuildArea\Output\SampleToolGui.exe /o:D:\dotNetDelivery\BuildArea\Reports\fxcop.xml /r:D:\dotNetDelivery\Tools\FxCop\1.30\Rules\" failonerror="false"/>

<style style="D:\dotNetDelivery\Tools\FxCop\1.30\Xml\FxCopReport.xsl" in="D:\dotNetDelivery\BuildArea\Reports\fxcop.xml" out="D:\dotNetDelivery\BuildArea\Reports\fxcop.html"/>

<property name="nant.onfailure" value="fail"/>

</target>

<target name="document" description="Generate documentation and reports.">
<ndoc>
<assemblies basedir="D:\dotNetDelivery\BuildArea\Output\">
                <include name="SampleToolEngine.dll" />
                <include name="SampleToolGui.dll" />
            </assemblies>
            <summaries basedir="D:\dotNetDelivery\BuildArea\Output\">
                <include name="SampleToolEngine.xml" />
                <include name="SampleToolGui.xml" />
            </summaries>
            <documenters>
                <documenter name="MSDN">
                    <property name="OutputDirectory" value="D:\dotNetDelivery\BuildArea\Docs\" />
                    <property name="HtmlHelpName" value="SampleTool" />
                    <property name="HtmlHelpCompilerFilename" value="hhc.exe" />
                    <property name="IncludeFavorites" value="False" />
                    <property name="Title" value="SampleTool (NDoc)" />
                    <property name="SplitTOCs" value="False" />
                    <property name="DefaulTOC" value="" />
                    <property name="ShowVisualBasic" value="False" />
                    <property name="ShowMissingSummaries" value="True" />
                    <property name="ShowMissingRemarks" value="False" />
                    <property name="ShowMissingParams" value="True" />
                    <property name="ShowMissingReturns" value="True" />
                    <property name="ShowMissingValues" value="True" />
                    <property name="DocumentInternals" value="True" />
                    <property name="DocumentProtected" value="True" />
                    <property name="DocumentPrivates" value="False" />
                    <property name="DocumentEmptyNamespaces" value="False" />
                    <property name="IncludeAssemblyVersion" value="True" />
                    <property name="CopyrightText" value="Etomic Ltd., 2005" />
                    <property name="CopyrightHref" value="" />
                </documenter>
            </documenters>
        </ndoc>
</target>

<target name="publish" description="Place the compiled assets in agreed location.">
<copy todir="D:\dotNetDelivery\BuildArea\Distribution\">
<fileset basedir="D:\dotNetDelivery\BuildArea\Output\">
<include name="SampleToolEngine.dll"/>
<include name="SampleToolGui.exe"/>
</fileset>
</copy>

<zip zipfile="D:\dotNetDelivery\BuildArea\Publish\SampleTool-Build-${sys.version}.zip">
<fileset basedir="D:\dotNetDelivery\BuildArea\Distribution\">
<include name="**" />
</fileset>
</zip>
</target>

<target name="notify" description="Tell everyone of the success or failure.">
<echo message="Notifying you of the build process success."/>
</target>

<target name="fail">
<echo message="Notifying you of a failure in the build process."/>
</target>

<target name="fail.test">
<nunit2report out="D:\dotNetDelivery\BuildArea\Reports\NUnit.html">
<fileset>
<include name="D:\dotNetDelivery\BuildArea\Reports\SampleToolTests.dll-results.xml" />
</fileset>
</nunit2report>
</target>

<target name="help">
<echo message="The skeleton file for the build process is designed to execute the following targets in turn:"/>
<echo message="-- clean"/>
<echo message="-- get"/>
<echo message="-- version"/>
<echo message="-- build"/>
<echo message="-- test"/>
<echo message="-- document"/>
<echo message="-- publish"/>
<echo message="-- notify"/>
<echo message="This file should be run with a Boolean value for 'debug'."/>
<echo message="-- True indicates that no versioning be set (0.0.0.0)."/>
<echo message="-- False indicates that a regular version be set(1.0.x.0)."/>
<echo message="Example: -D:debug=true"/>
</target>

</project> 

Friday, February 22, 2013

Setting up NAnt on your pc/server

In this post we are going to see how to set up NANT on your PC/Server. Its first step towards Build Automation.



1.       Download Nant Binaries from http://nant.sourceforge.net/


2.       Once you download all Binary files, right click on Zip file and open Properties as show below


3.       Once properties window opens click on Unblock button as shown below



4.       Now unzip the Zipped file contents at some preferred location for eg. C:\Program Files (x86)\ Nant, as show below.




5.       Now go to “My Computer “ => “Advanced System Settings” => “Environment Variables”
And add following “System variable” as shown below


6.       Edit “Path” Variable in System Variables section as show below, append newly added system variable in your existing paths

 

7.       Open a command prompt and type “Nant – help”, you should see o/p like this.



Friday, February 15, 2013

LINQ to Excell


I am going to share a code sample where I am going to read data from excell and use Linq Query to process that data.

            //declaring all variables that I will use
            Workbook workBook;
            IEnumerable<Sheet> workSheets;
            WorksheetPart excelSheet;
            string excellsheetid;
            List<FormTag> tags;
            SharedStringTable sharedStrings;

            //Code to open Excel File
              using (SpreadsheetDocument document =
                SpreadsheetDocument.Open(
                    @"C:\Temp\TestExcel.xlsx",
                    true))
              {
                  //References to the workbook and Shared String Table.
                  workBook = document.WorkbookPart.Workbook;
                  workSheets = workBook.Descendants<Sheet>();
                  sharedStrings = document.WorkbookPart.SharedStringTablePart.SharedStringTable;

                  //Reference to Excel Worksheet with Customer data.
                  excellsheetid =
                      workSheets.First(s => s.Name == "Sheet1").Id;

                  //Reading Excell Sheet
                  excelSheet =
                      (WorksheetPart)document.WorkbookPart.GetPartById(excellsheetid);


                  //LINQ query to skip first row with column names.
                  IEnumerable<Row> dataRows =
                      from row in excelSheet.Worksheet.Descendants<Row>()
                      where row.RowIndex > 1
                      select row;

                  //Looping through all rows after eliminating first row..assuming first row is a header row
                  foreach (Row row in dataRows)
                  {
                      //LINQ query to return the row's cell values.
                      //Where clause filters out any cells that do not contain a value.
                      //Select returns the value of a cell unless the cell contains
                      //  a Shared String.
                      //If the cell contains a Shared String, its value will be a 
                      //  reference id which will be used to look up the value in the 
                      //  Shared String table.
                      IEnumerable<String> textValues =
                          from cell in row.Descendants<Cell>()
                          where cell.CellValue != null
                          select
                              (cell.DataType != null
                               && cell.DataType.HasValue
                               && cell.DataType == CellValues.SharedString
                                   ? sharedStrings.ChildElements[
                                       int.Parse(cell.CellValue.InnerText)].InnerText
                                   : cell.CellValue.InnerText)
                          ;

                      //Check to verify the row contained data.
                      if (textValues.Count() > 0)
                      {
                          //Create your object for eg. a customer object and and manipulate it.
                          var textArray = textValues.ToArray();
                          Cutomer cust = new Cutomer();
                          cust.CustId = textArray[0];
                          cust.CustName = textArray[1];
                      }
                      else
                      {
                          //If no cells, then you have reached the end of the table.
                          break;
                      }
                  }
                  
              }

Wednesday, January 23, 2013

Using SQL Server Windowing Function with Aggregates Function

In this post we will see how we can use SQL Server Windowing function in conjunction with Aggregate functions. In SQL Server 2005 Windowing (Over Clause) was supported with all Aggregate functions (Avg , Count, Min, Max and Sum) , in SQL Server 2012 it got further better with support of "Order By" Clause.


Let's look at some Query and their O/P..

Query

1. Lets Create a TransData Table, with following Schema


CREATE TABLE TransData (AcctId int, TransDate date, Amount decimal)
INSERT INTO TransData (AcctId, TransDate, Amount) VALUES
  (1, DATEFROMPARTS(2011, 8, 10), 500),  -- 5 transactions for acct 1
  (1, DATEFROMPARTS(2011, 8, 22), 250),
  (1, DATEFROMPARTS(2011, 8, 24), 75),
  (1, DATEFROMPARTS(2011, 8, 26), 125),
  (1, DATEFROMPARTS(2011, 8, 28), 175),
  (2, DATEFROMPARTS(2011, 8, 11), 500),  -- 8 transactions for acct 2
  (2, DATEFROMPARTS(2011, 8, 15), 50),
  (2, DATEFROMPARTS(2011, 8, 22), 5000),
  (2, DATEFROMPARTS(2011, 8, 25), 550),
  (2, DATEFROMPARTS(2011, 8, 27), 105),
  (2, DATEFROMPARTS(2011, 8, 27), 95),
  (2, DATEFROMPARTS(2011, 8, 29), 100),
  (2, DATEFROMPARTS(2011, 8, 30), 2500),
  (3, DATEFROMPARTS(2011, 8, 14), 500),  -- 4 transactions for acct 3
  (3, DATEFROMPARTS(2011, 8, 15), 600),
  (3, DATEFROMPARTS(2011, 8, 22), 25),
  (3, DATEFROMPARTS(2011, 8, 23), 125)


2. Now we write a Query which will partition data by AccountId and Order them by TransDate


SELECT AcctId, TxnDate, Amount,
  RAvg = AVG(Amount) OVER (PARTITION BY AcctId ORDER BY TxnDate),
  RCnt = COUNT(*)    OVER (PARTITION BY AcctId ORDER BY TxnDate),
  RMin = MIN(Amount) OVER (PARTITION BY AcctId ORDER BY TxnDate),
  RMax = MAX(Amount) OVER (PARTITION BY AcctId ORDER BY TxnDate),
  RSum = SUM(Amount) OVER (PARTITION BY AcctId ORDER BY TxnDate)
 FROM TxnData
 ORDER BY AcctId, TxnDate
GO

3. Here is the O/P of above Query





Friday, January 11, 2013

Delegates in C#



A method that is specified in an interface is implemented with the same name in the
base class. However, such close coupling is not always appropriate. The delegate construct
can be used to break the coupling for this purpose.

A delegate is a type that
defines a method signature. A delegate instance is then able to accept a method of that
signature, regardless of its method name or the type that encapsulates it.
The delegate syntax in C# evolved considerably from Versions 1.0 to 2.0 to 3.0. We
shall concentrate on the 3.0 version, which is the simplest to code. The language has
predefined standard generic delegate types, as follows:

        delegate R Func<R>();
        delegate R Func<A1, R>(A1 a1);
        delegate R Func<A1, A2, R>(A1 a1, A2 a2);
        // ... and up to 16 arguments

where R is the return type and the As and as represent the argument types and names,
respectively. Thus, declaring a delegate instance is now straightforward. For example,
we can define a Request delegate that takes an integer parameter and returns a string:

public Func<int, string> Request;

Next, we can assign an actual method to Request, as in:

Request = Target.Estimate;

The delegate can then be invoked just as any other method would be:

string s = Request(5);

This statement would invoke the Estimate method in the Target class, returning a
string.


Anonymous functions simplify the creation of one-time behavior for delegates. They are
useful when additional behavior is to be added before or after a method is invoked. For
example:

Request = delegate(int i) {
return "Estimate based on precision is " +
(int) Math.Round(Precise (i,3));
};

Here, the method to be invoked is Precise. The parameters are different from the ones
in the delegate, as is the return value. The anonymous function can wrapupthe
changes and assign a “complete solution” to the delegate for later invocation.


Delegates are used extensively in Windows GUI event-driven programming, where
they reflect the need to call back into the user’s code when some event happens.
Mostly, existing code of this type will use an older syntax. Also, because the new Func
delegates must have return types, void delegates must use the original syntax too. Consider
a simple example of wanting to inform one object that input has occurred in
another object (this is part of Example 4-4). We first declare a delegate visible to both
classes:

public delegate void InputEventHandler(object sender, EventArgs e, string s);

Then, in the class where the event is handled, we create an instance of the delegate and
add it to the event object of the class that will receive the event. When creating the delegate,
we indicate the method that it will call (in this case, OnInput):


   visuals.InputEvent += new InputEventHandler(OnInput);

        void OnInput(object sender, EventArgs e, string s)
        {
            // Do something
        }



The signature of OnInput must match that of InputEventHandler, which it does. Now,
in the class where event occurs, we declare the event:


       public event InputEventHandler InputEvent;

and in some method we invoke it:


       public void Input(object source, EventArgs e)
       {
           InputEvent(this, EventArgs.Empty, who);
       }

The action of invoking the InputEvent delegate causes the method currently assigned
to it (here, OnInput) to be invoked. Thus, the callback from one class to the other is
achieved.

More than one method can be associated with a delegate; when such a delegate is
invoked, all its methods are called. Thus, if another object needed to know about input
in the preceding example, it could add its own handler method on to InputEvent using
+=. Event handlers can be removed using -=

Adapter Design Pattern

The Adapter pattern helps in Integrating 2 classes which have altogether different Interfaces. It’s useful for off-the-shelf code, for toolkits, and for libraries.  Generally Toolkit or 3rd Party controls needs a lot of adaptor classes as in many scenario it’s not possible to use Toolkit’s interfaces.

Design:
In following UML class diagram , we have a Client class and Adaptee class. Adaptee class has method “SepecificRequest” which needs to be called by Client class. Client class uses an Adaptor class which implements ITarget interface and exposes Request method. Adapter class implements Request method and it’s a child object in Client Class. So, Client doesn’t need to know anything about Adaptee class all it has to know is about ITarget interface and Request method.


Implementation:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    // Existing way requests are implemented
    class Adaptee
    {
        // Provide full precision
        public double SpecificRequest(double a, double b)
        {
            return a / b;
        }
    }

    // Required standard for requests
    interface ITarget
    {
        // Rough estimate required
        string Request(int i);
    }

    // Implementing the required standard via Adaptee
    class Adapter : Adaptee, ITarget
    {
        public string Request(int i)
        {
            return "Rough estimate is " + (int)Math.Round(SpecificRequest(i, 3));
        }
    }

    class Client
    {
        public void CallRequest()
        {
            // Showing the Adapteee in standalone mode
            Adaptee first = new Adaptee();
            Console.Write("Before the new standard\nPrecise reading: ");
            Console.WriteLine(first.SpecificRequest(5, 3));

            // What the client really wants
            ITarget second = new Adapter();
            Console.WriteLine("\nMoving to the new standard");
            Console.WriteLine(second.Request(5));
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Client cl = new Client();
            cl.CallRequest();
            Console.Read();
        }
    }
}


Output:


Depending on their Usage, there are following 2 types of Adapter classes

1) Pluggable Adapters : Developers who recognize that their systems will need to work with other components can increase their chances of adaptation. Identifying in advance the parts of the system that might change makes it easier to plug in adapters for a variety of new situations.

Keeping down the size of an interface also increases the opportunities for new
systems to be plugged in. Although not technically different from ordinary adapters, this feature of small interfaces gives them the name pluggable adapters.
A distinguishing feature of pluggable adapters is that the name of a method called by the client and that existing in the ITarget interface can be different. The adapter must be able to handle the name change. In the previous adapter variations, this was true for all Adaptee methods, but the client had to use the names in the ITarget interface.
Suppose the client wants to use its own names, or that there is more than one client and they have different terminologies.



2) Two-Way Adapters : Adapters provide access to some behavior in the Adaptee (the behavior required in the ITarget interface), but Adapter objects are not interchangeable with Adaptee objects. They cannot be used where Adaptee objects can because they work on the implementation of the Adaptee, not its interface. Sometimes we need to have objects
that can be transparently ITarget or Adaptee objects. 

This could be easily achieved if the Adapter inherited both interfaces; however, such multiple inheritance is not possible in C#, so we must look at other solutions.

The two-way adapter addresses the problem of two systems where the characteristics of one system have to be used in the other, and vice versa. An  Adapter class is set up to absorb the important common methods of both and to provide adaptations to both. The resulting adapter objects will be Acceptable to both sides. Theoretically, this idea can be extended to more than two systems, so we can have multiway adapters, but there are some implementation limitations: without multiple inheritance, we have to insert an interface between each original class and the adapter.