C# version 4

See what's new in C#4

Table of contents

Dynamic binding

A variable with dynamic type can be assigned any type.

dynamic f = 1;
((object)f).Dump("F is an integer?");

f = "F is a string";
((object)f).Dump("F is a string NOW?");

Note that in Linqpad to dump a dynamic you can cast it to object.

A handy type in the System.Dynamic namespace is ExpandoObject

dynamic idea = new ExpandoObject();
idea.Who = "Me";
idea.When = DateTime.Now;
((object)idea).Dump();

(Again, cast to object to be able to dump in linqpad)

Named/optional arguments

This is a bit of a contrived example, don't do this in production.

Given this method... note the default value supplied to some arguments... that makes those arguments optional:

public void LogDetails(string message, ConsoleColor color = ConsoleColor.Gray, ConsoleColor bgColor = ConsoleColor.Black) {
	Console.ForegroundColor = color;
	Console.BackgroundColor = bgColor;
	Console.WriteLine(message);
	Console.ResetColor();
}

We can specify just the first argument, omitting all the optional arguments:

LogDetails("Hey");

We can omit just the last argument...

LogDetails("Oh no!", ConsoleColor.Red);

To omit an argument in the middle, we need to use the naming feature:

LogDetails("Exciting", bgColor: ConsoleColor.Magenta);

We can use naming to specify the arguments in whatever order we feel like specifying them....

LogDetails(bgColor: ConsoleColor.DarkBlue, color: ConsoleColor.Yellow, message: "This is a message");

...but I would generally avoid that.

Generic covariant and contravariant

See https://stackoverflow.com/questions/2662369/covariance-and-contravariance-real-world-example

...my favored answer there is a lengthy one, but it provides a rationale as well: https://stackoverflow.com/a/42660356

Examples:

This means a method that accepts a parameter IList<Feline> will only accept exactly that. It won't accept IList<Tiger> (more derived) and it won't accept IList<Object> less derived.

Meanwhile:

This means a method that expects IEnumerable<Feline> will accept IEnumerable<Feline> or IEnumerable<Tiger> or IEnumerable<HouseCat> because these are more derived. It won't accept IEnumerable<Object> (less derived)

And conversely....

This means a method with a parameter that is Action<Feline> will accept Action<Feline> or Action<Mammal> (assuming Felines inherits from Mammal, inherits from Animal, inherits from Object) -- and will ALSO accept Action<Animal> and even Action<Object> but it will not accept a parameters of type Action<HouseCat> or a parameter of type Action<Tiger> because these are MORE derived.

Embedded interop types

Type equivalence and embedded interop types

If you publish a COM component, you no longer need to publish a primary interop assembly to be accessible from .net (unless you want it to be accessed from earlier versions)

Hard to summarize, and unless you're publishing or using a lot of COM components, the nuances here are likely to escape you. I'm gonna skip going in great depth on this one.

Sources

See also

And: