Welcome

Hello, Welcome to my blog. If you like feel free to refer others

Tuesday 27 November 2012

window.showModalDialog Page Load not being executed everytime

Problem : Loading a page as a modal dialog box as window.showModalDialog("myurl.aspx"). The first time the modal dialog is poped up the page load event gets called. When i close it and call the same again, the Control does not come to the Page_Load(). Instead the page pops up with the previous values in all its controls. What we want is the Page_Load() to be triggered every time the modal dialog pops up.

Solution: First of all showModalDialog is an proprietary IE only feature its not supported by all browsers

Solution 1 :   You need to add a unique query string value to the URL that you are using to avoid IE showing the cached version. So generate a random number and append it to the URL e.g myurl.aspx?rnd=12237827348273. This should bust the cache and make a fresh request

Solution 2 : Turn caching of on the page by using @OutputCache directive 

<%@ OutputCache Duration="1" Location="None" VaryByParam="none" %>

Solution 3 :  Call----- Response.Cache.SetCacheability(HttpCacheability.NoCache);


Hope that will help you. Happy Learning...... :)

Monday 26 November 2012

Dropdown list binding with financial year

Problem: Sometimes we need to get a result of financial years(...2011-2012, 2012-2013, 2013-2014) starting from the date given by me to till 5 year in a dropdown list.

Solution: Lets say we received the given date from text box:-
 
DateTime GivenDate = Convert.ToDateTime(textBox1.Text);
int GivenYear = GivenDate.Year;
 
for(int i=0; i<5; i++)
{
comboBox1.Items.Add(GivenYear + i + "-" + (GivenYear + 1 + i));
}

Hope this will solve your problem.....

Thursday 18 October 2012

'Operation is not valid due to the current state of the object' error during postback

Whenever a postback is done, this error occurs when form fields are very large in number. The stack trace is:
at System.Web.HttpValueCollection.ThrowIfMaxHttpCollectionKeysExceeded() at System.Web.HttpValueCollection.FillFromEncodedBytes(Byte[] bytes, Encoding encoding) at System.Web.HttpRequest.FillInFormCollection()
By default, the maximum value of MaxHttpCollection is 1000.
To solve this error, increase the MaxHttpCollection value. Try adding the following setting in your web.config's <appsettings> block.
<appSettings>
    <add key="aspnet:MaxHttpCollectionKeys" value="2001" />
</appSettings>
 
It can solve your problem. If you have very large records on your page, say 600 records in a grid, and you click on Submit, then increase the value of MaxHttpCollection.
Then change value 2000 to 5000 and test again. It will be resolved. 

Question : Specifying MaxHttpCollectionKeys for a specific page - is this possible? 

No, that's not possible. It always checks the appSetting aspnet:MaxHttpCollectionKeys and if that is missing it will be set to 1000. You cannot override this because the reading of the setting and the default value is done inside an internal class.

Perhaps a better approach would be to build a form with less than 1000 items. Maybe in the form of a wizard. Or maybe by combining multiple values into a single data structure and deserializing it on the server.

for more info please visit the link

Happy learning....... :)


Tuesday 16 October 2012

Remove Duplicate Rows from a Table in SQL Server

--Create Table Script
CREATE TABLE [dbo].[ATTENDANCE](
    [AUTOID] INT IDENTITY(1,1),
    [EMPLOYEE_ID] [varchar](50) NOT NULL,
    [ATTENDANCE_DATE] [date] NOT NULL
) ON [PRIMARY] 

--Insert the into the newly created table
INSERT INTO dbo.ATTENDANCE (EMPLOYEE_ID,ATTENDANCE_DATE)VALUES
            ('A001',CONVERT(DATETIME,'01-01-11',5))
INSERT INTO dbo.ATTENDANCE (EMPLOYEE_ID,ATTENDANCE_DATE)VALUES
            ('A001',CONVERT(DATETIME,'01-01-11',5))
INSERT INTO dbo.ATTENDANCE (EMPLOYEE_ID,ATTENDANCE_DATE)VALUES
            ('A002',CONVERT(DATETIME,'01-01-11',5))
INSERT INTO dbo.ATTENDANCE (EMPLOYEE_ID,ATTENDANCE_DATE)VALUES
            ('A002',CONVERT(DATETIME,'01-01-11',5))
INSERT INTO dbo.ATTENDANCE (EMPLOYEE_ID,ATTENDANCE_DATE)VALUES
            ('A002',CONVERT(DATETIME,'01-01-11',5))
INSERT INTO dbo.ATTENDANCE (EMPLOYEE_ID,ATTENDANCE_DATE)VALUES
            ('A003',CONVERT(DATETIME,'01-01-11',5))

--Check the data from the table            
SELECT * FROM dbo.ATTENDANCE

--Check the duplicate data
SELECT * FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID)
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 

--Delete the duplicate data
DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID)
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE)

--Alternatively you can use the below query as well
DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MAX(AUTOID)
FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE)

--After deleting the duplicate data check data from the table
SELECT * FROM dbo.ATTENDANCE



So in general use the below Query-
DELETE
FROM MyTable
WHERE ID NOT IN
(
SELECT MAX(ID)
FROM MyTable
GROUP BY DuplicateColumn1, DuplicateColumn2, DuplicateColumn3)


Table in example is has ID as Identity Column and Columns which have duplicate data are DuplicateColumn1, DuplicateColumn2 and DuplicateColumn3. 


Happy learning..... :) 

Tuesday 9 October 2012

WCF - The type name ServiceReference1 does not exist in the type Namespace.ClassName


This is a short blog post about a strange error when adding a WCF service reference. A WCF service was created and I wanted to add a service reference to a client project. I added the reference through Visual Studio and everything went fine until I compiled. Then I got this error:

Error    1    The type name 'ServiceReference1' does not exist in the type 'FeedbackCustomControl.FeedbackCustomControl'    D:\RND\ExcelApplication\FeedbackCustomControl\Service References\ServiceReference1\Reference.cs    146    46    FeedbackCustomControl


I found that this is caused by me having the same namespace name as class name (FeedbackCustomControl.FeedbackCustomControl = Namespace.ClassName). Change your namespace to a name that is not the same name as your class and this will compile.

Happy Learning..... :)






Wednesday 5 September 2012

The shortest, fastest, and easiest way to compare two tables in SQL Server


When you have two tables (or resultsets from SELECT statements) that you wish to compare, and you want to see any changes in ANY columns, as well as to see which rows exist in 1 table but not the other (in either direction) I have found that the UNION operator works quite well.
UNION allows you to compare all columns very quickly, and also handles comparing NULL values to other NULLs successfully, which a join clause or a WHERE condition doesn't normally do.  It also allows you to very quickly see which rows are missing in either table, which only a FULL OUTER JOIN will do, but of course we all know to avoid those at all costs (right?) -- a full outer join is about as “unrelational” as you can get.  (every column returned is potentially Null and must be wrapped in a COALESCE function).  Best of all, the UNION is quick and easy and short.
The basic idea is: if we GROUP the union of two tables on all columns, then if the two tables are identical all groups will result in a COUNT(*) of 2.  But for any rows that are not completely matched on any column in the GROUP BY clause, the COUNT(*) will be 1 -- and those are the ones we want.  We also need to add a column to each part of the UNION to indicate which table each row comes from, otherwise there is no way to distinguish between which row comes from which table.


CREATE PROCEDURE CompareTables(@table1 varchar(100),
 @table2 Varchar(100), @T1ColumnList varchar(1000),
 @T2ColumnList varchar(1000) = '')
AS
declare @SQL varchar(8000);

IF @t2ColumnList = '' SET @T2ColumnList = @T1ColumnList

set @SQL = 'SELECT ''' + @table1 + ''' AS TableName, ' + @t1ColumnList +
 ' FROM ' + @Table1 + ' UNION ALL SELECT ''' + @table2 + ''' As TableName, ' +
 @t2ColumnList + ' FROM ' + @Table2

set @SQL = 'SELECT Max(TableName) as TableName, ' + @t1ColumnList +
 ' FROM (' + @SQL + ') A GROUP BY ' + @t1ColumnList +
 ' HAVING COUNT(*) = 1'

exec ( @SQL)

Parameter definition:

-- Table1, Table2 are the tables or views to compare.
-- T1ColumnList is the list of columns to compare, from table1.
-- Just list them comma-separated, like in a GROUP BY clause.
-- If T2ColumnList is not specified, it is assumed to be the same
-- as T1ColumnList.  Otherwise, list the columns of Table2 in
-- the same order as the columns in table1 that you wish to compare.
--
-- The result is all rows from either table that do NOT match
-- the other table in all columns specified, along with which table that row is from.






Happy learning......

Tuesday 7 August 2012

Nested user controls and javascript getElementById

This is the code to find control in WebUserControl which nested in your aspx page.
Suppose the popup.ascx's ID is popupControl and the locations.ascx's ID is locationControl
To find "drpLocationList" which in location.ascx we can use the below mentioned code:

var ddlLocation = document.getElementById('<%=popupControl.FindControl("locationControl").FindControl("drpLocationList").ClientID%>');

Disable History on Textbox

For Framework version 2.0 and above: 
Set the AutoCompleteType property to Disabled for the textbox.
AutoCompleteType="Disabled"

For other framework version :

TextBox1.Attributes.Add("autocomplete", "off")

Wednesday 27 June 2012

Printing the content of div or panel

In general, we required to print the content of a portion of page. We don't need that whole page will get printed. So here I am going to provide a small java script function that can solve this problem.
Here is the code for print a specific area.

function PrintDiv() {    
var prtContent = document.getElementById('<%=divPrintArea.ClientID%>');   
var WinPrint = window.open('', '', 'left=0,top=0,width=900,height=600,
toolbar=1,scrollbars=1,status=0');    
WinPrint.document.write(prtContent.innerHTML);    
WinPrint.document.close();   
WinPrint.focus();   
WinPrint.print();   
WinPrint.close();    
}

Javascript function to check integer value

function isInteger(s) {
    var i;
    for (i = 0; i < s.length; i++) {
        // Check that current character is number.
        var c = s.charAt(i);
        if (((c < "0") || (c > "9"))) return false;
    }
    // All characters are numbers.
    return true;
}

Making a button default clickable when enter key is pressed

Many times we want that on pressing enter key the submit button should be automatic click. For example on login page after typing password generally users press enter key and want that submit button will call but nothing happen.
 Here is the JavaScript code for it:


function doClick(buttonName, e) {
            var key;
            if (window.event)
                        key = window.event.keyCode;     //IE
            else
                        key = e.which;     //firefox
            if (key == 13) {   //Get the button the user wants to have clicked
                        var btn = document.getElementById(buttonName);
                        if (btn != null) { //If we find the button click it
                                    btn.click();
                                    event.keyCode = 0
                        }
            }
}

Tuesday 26 June 2012

How to check if a string contains special character using javascript


Sometimes we need to check if a string contains any special charachter. Ex. name should not contains any special character.

Here is the code for it : 

function IsSpecialChar(strString)
//  check for valid SpecialChar strings
{
    var strValidChars = "<>@!#$%^&*()_+[]{}?:;|'\"\\,./~`-=";
    var strChar;
    var blnResult = true;

    if (strString.length == 0) return false;

    //  test strString consists of valid characters listed above
    for (i = 0; i < strString.length && blnResult == true; i++) {
        strChar = strString.charAt(i);
        if (strValidChars.indexOf(strChar) == -1) {
            blnResult = false;
        }
    }
    return blnResult;
}




Happy Learning......

Friday 16 March 2012

How to stop the !New tag from appearing when you add items to your SharePoint Team Services and SharePoint Services Web site

To stop the !New tag from appearing for new entries on your Windows SharePoint Services Web site, follow these steps, as appropriate for your version of SharePoint Services.

Windows SharePoint Services 3.0 Web site

To stop the !New tag from appearing next to new entries on a Windows SharePoint Services 3.0 Web site, use the Stsadm.exe tool to change the "Days to Show New Icon" property to zero. 

To do this, follow these steps:
  1. Click Start, point to All Programs, point to Accessories, and then click Command Prompt.
  2. Type the following commands, and then press ENTER after each command:
    cd /d %programfiles%\Common Files\Microsoft Shared\Web Server Extensions\12\BIN
    stsadm.exe -o setproperty -pn days-to-show-new-icon -pv 0 -url [Your Virtual Server's URL]

Windows SharePoint Services Web site

To stop the !New tag from appearing next to new entries on a Windows SharePoint Services Web site, use the Stsadm.exe tool to change the "Days to Show New Icon" property to zero. 

To do this, follow these steps:
  1. Click Start, point to All Programs, point to Accessories, and then click Command Prompt.
  2. Type the following commands, and then press ENTER after each command:
    cd /d %programfiles%\Common Files\Microsoft Shared\Web Server Extensions\60\BIN
    stsadm.exe -o setproperty -pn days-to-show-new-icon -pv 0 -url [Your Virtual Server's URL]

SharePoint Team Services Web site

To stop the !New tag from appearing next to new entries on a SharePoint Team Services Web site, use the Owsadm.exe tool to change the "New Item Display Cutoff" property to zero.

To do this, follow these steps:
  1. Click Start, point to All Programs, point to Accessories, and then click Command Prompt.
  2. Type the following commands, and then press ENTER after each command:
    cd /d %programfiles%\Common Files\Microsoft Shared\Web Server Extensions\50\BIN
    owsadm.exe -o setproperty -pn NewItemDisplayCutoff -pv 0 -p [Your Virtual Server's Port]

    Source : msdn

Thursday 9 February 2012

Creating Shared Assembly or GAC Assembly and accessing


Creating an assembly key file

The steps involved in adding an assembly to the GAC is not as simple as adding the assembly to a web application. Since all applications can access this library, some security precautions have been taken by Microsoft to ensure uniqueness, version protection, and code integrity. This is achieved by creating a strong name for your new assembly. A Strong Name consists of the assembly identity and also a public key and digital signature. To create a strong name, you use the syntax:
sn -k StrongNameFile.snk
Adding StrongNameFile.snk entry and modifying the version in AssemblyInfo.cs
[assembly: AssemblyVersion("1.0.1.1")]
[assembly: AssemblyKeyFile("c:\\StrongNameFile.snk")]

Adding your assembly to your GAC
gacutil /i AssemblyFileName.dll

Adding your assembly machine.config
<assembly="AssemblyFileName,Version=0.0.0.0,Culture=neutral,PublicKeyToken=5edf592a9c40680c">
Using Shared Assembly

<%@Import Namespace="Ashis"%>

Happy learning......

Insert IDENTITY column by IDENTITY_INSERT ON


Problem: If a column in a table have identity on a


Explanation:


CREATE TABLE dbo.Tool(
   ID INT IDENTITY NOT NULL PRIMARY KEY,
   Name VARCHAR(40) NOT NULL
)
GO
-- Inserting values into products table.
INSERT INTO dbo.Tool(Name) VALUES ('Screwdriver')
INSERT INTO dbo.Tool(Name) VALUES ('Hammer')
INSERT INTO dbo.Tool(Name) VALUES ('Saw')
INSERT INTO dbo.Tool(Name) VALUES ('Shovel')
GO

-- Create a gap in the identity values.
DELETE dbo.Tool
WHERE Name = 'Saw'
GO

SELECT *
FROM dbo.Tool
GO

-- Try to insert an explicit ID value of 3;
-- should return a warning.
INSERT INTO dbo.Tool (ID, Name) VALUES (3, 'Garden shovel')
GO
-- SET IDENTITY_INSERT to ON.
SET IDENTITY_INSERT dbo.Tool ON
GO

-- Try to insert an explicit ID value of 3.
INSERT INTO dbo.Tool (ID, Name) VALUES (3, 'Garden shovel')
GO

SELECT *
FROM dbo.Tool
GO
-- Drop products table.
DROP TABLE dbo.Tool
GO



Happy Learning......

C# 4.0's Main Features

Overall there are four main features that are introduced in the upcoming C# 4.0:
1.    Dynamic Typed Objects
2.    Optional and Named Parameters
3.    Improved COM Interoperability
4.    Co- and Contra-Variance


1.    Dynamic Typed Objects

After the introduction of "var" in C# 3.5, the use of anonymous types increased rapidly. But as C# doesn't truly supporting the dynamic types, which means the types will be determined during the runtime and any error that is produced will not affect compilation of the project, there were lots of limitations. var is determined during compile time, and it is implicitly typed variable so it can’t be a return type of a method. Dynamic on the other hand can be a part of return type or argument of a method and will act during runtime when actual object is set to it.


The dynamic keyword is new to C# 4.0, and is used to tell the compiler that a variable's type can change or that it is not known until runtime. Think of it as being able to interact with an Object without having to cast it.

dynamic cust = GetCustomer();
cust.FirstName = "foo"; // works as expected
cust.Process(); // works as expected
cust.MissingMethod(); // No method found!

Notice we did not need to cast nor declare cust as type Customer. Because we declared it dynamic, the runtime takes over and then searches and sets the FirstName property for us. Now, of course, when you are using a dynamic variable, you are giving up compiler type checking. This means the call cust.MissingMethod() will compile and not fail until runtime. The result of this operation is a RuntimeBinderException because MissingMethod is not defined on the Customer class.

The example above shows how dynamic works when calling methods and properties. Another powerful (and potentially dangerous) feature is being able to reuse variables for different types of data. I'm sure the Python, Ruby, and Perl programmers out there can think of a million ways to take advantage of this, but I've been using C# so long that it just feels "wrong" to me.

dynamic foo = 123;
foo = "bar";

OK, so you most likely will not be writing code like the above very often. There may be times, however, when variable reuse can come in handy or clean up a dirty piece of legacy code. One simple case I run into often is constantly having to cast between decimal and double.

decimal foo = GetDecimalValue();
foo = foo / 2.5; // Does not compile
foo = Math.Sqrt(foo); // Does not compile
string bar = foo.ToString("c");

The second line does not compile because 2.5 is typed as a double and line 3 does not compile because Math.Sqrt expects a double. Obviously, all you have to do is cast and/or change your variable type, but there may be situations where dynamic makes sense to use.


dynamic foo = GetDecimalValue(); // still returns a decimal
foo = foo / 2.5; // The runtime takes care of this for us
foo = Math.Sqrt(foo); // Again, the DLR works its magic
string bar = foo.ToString("c");

Update

After some great questions and feedback, I realized I need to clarify a couple points I made above. When you use the dynamic keyword, you are invoking the new Dynamic Language Runtime libraries (DLR) in the .NET framework. There is plenty of information about the DLR out there, and I am not covering it in this article. Also, when possible, you should always cast your objects and take advantage of type checking. The examples above were meant to show how dynamic works and how you can create an example to test it. Over time, I'm sure best practices will emerge; I am making no attempt to create recommendations on the use of the DLR or dynamic.

Also, since publishing the initial version of this article, I have learned that if the object you declared as dynamic is a plain CLR object, Reflection will be used to locate members and not the DLR. Again, I am not attempting to make a deep dive into this subject, so please check other information sources if this interests you.

Switching Between Static and Dynamic

It should be apparent that 'switching' an object from being statically typed to dynamic is easy. After all, how hard is it to 'lose' information? Well, it turns out that going from dynamic to static is just as easy.

Customer cust = new Customer();
dynamic dynCust = cust; // static to dynamic, easy enough
dynCust.FirstName = "foo";
Customer newCustRef = dynCust; // Works because dynCust is a Customer
Person person = dynCust; // works because Customer inherits from Person
SalesRep rep = dynCust; // throws RuntimeBinderException exception
Note that in the example above, no matter how many different ways we reference it, we only have one Customer object (cust).

Functions

When you return something from a dynamic function call, indexer, etc., the result is always dynamic. Note that you can, of course, cast the result to a known type, but the object still starts out dynamic.


dynamic cust = GetCustomer();
string first = cust.FirstName; // conversion occurs
dynamic id = cust.CustomerId; // no conversion
object last = cust.LastName; //conversion occurs
There are, of course, a few missing features when it comes to dynamic types. Among them are:

Extension methods are not supported
Anonymous functions cannot be used as parameters
We will have to wait for the final version to see what other features get added or removed.

2.    Named and Optional Parameters

We'll start off with one of the easier features to explain. In fact, if you have ever used Visual Basic, then you are probably already familiar with it.

Optional Parameters

Support for optional parameters allows you to give a method parameter a default value so that you do not have to specify it every time you call the method. This comes in handy when you have overloaded methods that are chained together.

The Old Way

 public void Process( string data )
{
    Process( data, false );
}

public void Process( string data, bool ignoreWS )
{
    Process( data, ignoreWS, null );
}

public void Process( string data, bool ignoreWS, ArrayList moreData )
{
    // Actual work done here
}
The reason for overloading Process in this way is to avoid always having to include "false, null" in the third method call. Suppose 99% of the time there will not be 'moreData' provided. It seems ridiculous to type and pass null so many times.

// These 3 calls are equivalent
Process( "foo", false, null );
Process( "foo", false );
Process( "foo" );
The New Way

public void Process( string data, bool ignoreWS = false, ArrayList moreData = null )
{
    // Actual work done here
}
// Note: data must always be provided because it does not have a default value
Now we have one method instead of three, but the three ways we called Process above are still valid and still equivalent.

Process( "foo" ); // valid
Process( "foo", true ); // valid
Process( "foo", false, myArrayList ); // valid
Process( "foo", myArrayList ); // Invalid! See next section

Awesome, one less thing VB programmers can brag about having to themselves. I haven't mentioned it up to this point, but Microsoft has explicitly declared that VB and C# will be "co-evolving" so the number of disparate features is guaranteed to shrink over time. I would like to think this will render the VB vs. C# question moot, but I'm sure people will still find a way to argue about it. ;-)

Named Parameters

In the last example, we saw that the following call was invalid:

Process( "foo", myArrayList ); // Invalid!

But if the boolean ignoreWS is optional, why can't we just omit it? Well, one reason is for readability and maintainability, but primarily because it can become impossible to know what parameter you are specifying. If you had two parameters of the same type, or if one of the parameters was "object" or some other base class or interface, the compiler would not know which parameter you are sending. Imagine a method with ten optional parameters and you give it a single ArrayList. Since an ArrayList is also an object, an IList, and an IEnumerable, it is impossible to determine how to use it. Yes, the compiler could just pick the first valid option for each parameter (or a more complex system could be used), but this would become impossible for people to maintain and would cause countless programming mistakes.

Named parameters provide the solution:

ArrayList myArrayList = new ArrayList();
Process( "foo", true ); // valid, moreData omitted
Process( "foo", true, myArrayList ); // valid
Process( "foo", moreData: myArrayList); // valid, ignoreWS omitted
Process( "foo", moreData: myArrayList, ignoreWS: false ); // valid, but silly

As long as a parameter has a default value, it can be omitted, and you can just supply the parameters you want via their name. Note in the second line above, the 'true' value for ignoreWS did not have to be named since it is the next logical parameter.

3.    COM Interop

This is by far the area in which I have the least experience; however, I'm sure we have all had to interact with Microsoft Office at one point and make calls like this:

// Code simplified for this example
using Microsoft.Office.Interop;
using Microsoft.Office.Interop.Word;

object foo = "MyFile.txt";
object bar = Missing.Value;
object optional = Missing.Value;

Document doc = (Document)Application.GetDocument(ref foo, ref bar, ref optional);
doc.CheckSpelling(ref optional, ref optional, ref optional, ref optional);

There are (at least) three problems with the code above. First, you have to declare all your variables as objects and pass them with the ref keyword. Second, you can't omit parameters and must also pass the Missing.Value even if you are not using the parameter. And third, behind the scenes, you are using huge (in file size) interop assemblies just to make one method call.

C# 4.0 will allow you to write the code above in a much simpler form that ends up looking almost exactly like 'normal' C# code. This is accomplished by using some of the features already discussed; namely dynamic support and optional parameters.

// Again, simplified for example.
using Microsoft.Office.Interop.Word;

var doc = Application.GetDocument("MyFile.txt");
doc.CheckSpelling();

What will also happen behind the scenes is that the interop assembly that is generated will only include the interop code you are actually using in your application. This will cut down on application size tremendously. My apologies in advance for this weak COM example, but I hope it got the point across.

4.    Variance

Is the following legal in .NET?

// Example stolen from the whitepaper
IList<string> strings = new List<string>();
IList<object> objects = strings;

I think most of us, at first, would answer 'yes' because a string is an object. But the question we should be asking ourselves is: Is a -list- of strings a -list- of objects? To take it further: Is a -strongly typed- list of strings a -strongly typed- list of objects? When phrased that way, it's easier to understand why the answer to the question is 'no'. If the above example was legal, that means the following line would compile:

 objects.Add(123);

Oops, we just inserted the integer value 123 into a List<string>. Remember, the list contents were never copied; we simply have two references to the same list. There is a case, however, when casting the list, this should be allowed. If the list is read-only, then we should be allowed to view the contents any (type legal) way we want.

Co and Contra Variance

From Wikipedia:

Within the type system of a programming language, a type conversion operator is:

covariant if it preserves the ordering, =, of types, which orders types from more specific to more generic;
contravariant if it reverses this ordering, which orders types from more generic to more specific;
invariant if neither of these apply.

C# is, of course, covariant, meaning a Customer is a Person and can always be referenced as one. There are lots of discussions on this topic, and I will not cover it here. The changes in C# 4.0 only involve typed (generic) interfaces and delegates in situations like in the example above. In order to support co and contra variance, typed interfaces are going to be given 'input' and 'output' sides. So, to make the example above legal, IList must be declared in the following manner:


public interface IList<out T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
    ...
}
Notice the use of the out keyword. This is essentially saying the IList is readonly and it is safe to refer to a List<string> as a List<object>. Now, of course, IList is not going to be defined this way; it must support having items added to it. A better example to consider is IEnumerable which should be, and is, readonly.

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}
Using out to basically mean 'read only' is straightforward, but when does using the in keyword to make something 'write only' useful? Well, it actually becomes useful in situations where a generic argument is expected and only used internally by the method. IComparer is the canonical example.

public interface IComparer<in T>
{
    public int Compare(T left, T right);
}
As you can see, we can't get back an item of type T. Even though the Compare method could potentially act on the left and right arguments, it is kept within the method so it is a 'black hole' to clients that use the interface.

To continue the example above, this means that an IComparer<object> can be used in the place of an IComparer<string>. The C# 4.0 whitepaper sums the reason up nicely: 'If a comparer can compare any two objects, it can certainly also compare two strings'. This is counter-intuitive (or maybe contra-intuitive) because if a method expects a string, you can't give it an object.

Putting it Together

OK, comparing strings and objects is great, but I think a somewhat realistic example might help clarify how the new variance keywords are used. This first example demonstrates the effects of the redefined IEnumerable interface in C# 4.0. In .NET 3.5, line 3 below does not compile with an the error: 'can not convert List<Customer> to List<Person>'. As stated above, this seems 'wrong' because a Customer is a Person. In .NET 4.0, however, this exact same code compiles without any changes because IEnumerable is now defined with the out modifier.

MyInterface<Customer> customers = new MyClass<Customer>();
List<Person> people = new List<Person>();
people.AddRange(customers.GetAllTs()); // no in 3.5, yes in 4.0
people.Add(customers.GetAllTs()[0]); // yes in both
...
interface MyInterface<T>
{
    List<T> GetAllTs();
}
public class MyClass<T> : MyInterface<T>
{
    public List<T> GetAllTs()
    {
        return _data;
    }
    private List<T> _data = new List<T>();
}
This next example demonstrates how you can take advantage of the out keyword. In .NET 3.5, line 3 compiles, but line 4 does not with the same 'cannot convert' error. To make this work in .NET 4.0, simply change the declaration of MyInterface to interface MyInterface<out T>. Notice that in line 4, T is Person, but we are passing the Customer version of the class and interface.

MyInterface<Person> people = new MyClass<Person>();
MyInterface<Customer> customers = new MyClass<Customer>();
FooClass<Person>.GetThirdItem(people);
FooClass<Person>.GetThirdItem(customers);
...
public class FooClass<T>
{
    public static T GetThirdItem(MyInterface<T> foo)
    {
        return foo.GetItemAt(2);
    }
}
public interface MyInterface<out T>
{
    T GetItemAt(int index);
}
public class MyClass<T> : MyInterface<T>
{
    public T GetItemAt(int index)
    {
        return _data[index];
    }
    private List<T> _data = new List<T>();
}
This final example demonstrates the wacky logic of contravariance. Notice that we put a SalesRep 'inside' our Person interface. This isn't a problem because a SalesRep is a Person. Where it gets interesting is when we pass the MyInterface<Person> to FooClass<Customer>. In essence, we have 'inserted' a SalesRep into an interface declared to work with only Customers! In .NET 3.5, line 5 does not compile; as expected. By adding the in keyword to our interface declaration in .NET 4.0, everything works fine because we are 'agreeing' to treat everything as a Person internally and not expose the internal data (which might be that SalesRep).

MyInterface<Customer> customer = new MyClass<Customer>();
MyInterface<Person> person = new MyClass<Person>();
person.SetItem(new SalesRep());
FooClass<Customer>.Process(customer);
FooClass<Customer>.Process(person);
...
public class FooClass<T>
{
    public static void Process(MyInterface<T> obj)
    {
    }
}
public interface MyInterface<in T>
{
    void SetItem(T obj);
    void Copy(T obj);
}
public class MyClass<T> : MyInterface<T>
{
    public void SetItem(T obj)
    {
        _item = obj;
    }
    private T _item;
    public void Copy(T obj)
    {
    }
}


Happy learning......