New Features in C# 4.0
What's new in C# 4.0?
Dynamic type,
Optional and Named Parameters,
and
Invariance, Covariance and Contravariance
Although C# was born as a strongly typed language, "dynamic" allows us to create variables that are not strongly typed - the compiler will not scream if you invoke a function on a dynamic object without declaring it first. It will not complain when you try to stuff an integer and then follow that by putting in a string. The static type "dynamic" turns off static type checking (like certain government officials who can skip airport security or as Obi-Wan would say, "these aren't the types you're looking for"). "dynamic" is a contextual keyword, not a reserved keyword, so your old code with a variable named "dynamic" should run just fine. "dynamic" is used for interfacing with weakly typed CLR languages like Ruby, DOM objects, objects built by reflection like rehydration from XML, and objects built dynamically. This would not fly without "dynamic" If a method really is missing, the compiler doesn't complain, but when you execute the code, you will get a runtime error - just another reason to have all your code under unit tests. You can also catch the exception and have the "method-missing" functionality of Ruby. Another reason to use "dynamic" is to make code easier to read. Scott Hanselman, a national treasure, quotes Anders with this example: With "dynamic" it's much cleaner .Net 4.0 gives us the "ExpandoObject" in the Dynamic library. You can add methods as well to an ExpandoObject. You can now make method parameters optional by giving them a default: Before optional parameters, if you had a method which almost always took a particular value you'd have to do something like this: With optional parameters you can now get the same effect with If a value is not passed in, it is assumed to the be default. Optional parameters are great, but what if you have a dozen of them, and you only want to specify a few in the middle? Named Parameters to the rescue. Prefixing the variable name followed by a ":" clues in the compiler which variable we are passing. Another example - let's create a test user. Now instead of doing this You can do something much more compact. As an added benefit, it focuses the reader attention to the important variables being passed. Named parameters can also be used for documentation even when you don't have to use them, but it makes it easier for those who read the code. Now the reader doesn't have to remember which account is being taken from and which is being added to. (caveat: You can get into trouble with default values because the compiler simply inserts them into the calling code. If your function being called is in a different assembly, and it is updated with a new value, your code will need to be recompilied.) Type parameters in generic interfaces and generic delegates can be designated as covariant or contravariant by using "IN" and "OUT". Covariance is substituting a more dervived object for a less dervived object. This is a basic Object Oriented concept. If a function takes an Animal, you can pass a Tiger. Contravariance is substituting a less dervived object for a more dervived object. This was added to C# so the collection classes will act as we expect they should. Microsoft has a decent explaination here.The "dynamic" type
dynamic x = 10;
x = "asdf"; //compiler won't whine and it will run ok
dynamic x = 10;
int dynamic = 17;
Console.Out.WriteLine("dynamic = {0}", dynamic+x); //writes 27
dynamic penguin = new ExpandoObject();
penguin.fly(); //'System.Dynamic.ExpandoObject' does not contain a definition for 'fly'
object calc = GetCalculator();
Type calcType = calc.GetType();
object res = calcType.InvokeMember("Add",
BindingFlags.InvokeMethod, null,
new object[] { 10, 20 });
int sum = Convert.ToInt32(res);
dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);
using System.Dynamic;
...
dynamic house = new ExpandoObject(); //creates an object to which we can add fields and methods
house.squareFootage = 2100; //creates a new field on this object
Console.Out.WriteLine("house.squareFootage = {0}", house.squareFootage);
dynamic employee = new System.Dynamic.ExpandoObject();
employee.Address = "84 Rainey Street, Arlen, TX";
employee.Name = "Hank Hill";
employee.ToShippingLabel = (Func<string>)(() => employee.Name + "\r\n" + employee.Address);
Console.Out.WriteLine("employee.ToLabel = {0}", employee.ToShippingLabel());
Optional and Named Parameters
Optional Parameters
private static void Move(Bird bird, bool canFly)
private static void Move(Bird bird)
{
Move(bird, true);
}
private static void Move(Bird bird, bool canFly = true)
Move(myBird);
Named Parameters
private void Register(string name="Polly", string species="parrot", string color = "white") { ...}
...
Register(species: "dove");
static public int CreateTestUserId(string groupName = "Baseline", string ipAddress = "192.168.0.1",
string browser = "Chrome", string os = "mint", string language = "en-TX",
string status = "starting", string source = "LMS50", string pid = "mypid",
string pii = "", int test = 0, string machineName = "testMachineName",
string restrictionType = "u", string src = "101", string machineId = "testMachineId")
{...}
int userId = RDatabase.GetUserID("GroupX", "127.0.0." + i, "Opera-7.0", "WinNT", "en-UK", "Started", "LMS50", "abcdef", "-1", 1, "usausdt9999", null, "101a", Respondent.GetDebugMachineId("GetUserId"));
userId = RDatabase.CreateTestUserId(source: "ibm", pid: "abcdef", src: "101a");
MyDatabase.TransferMoney(from: account1, to: account2, amount: x);
Invariance, Covariance and Contravariance