C# version 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:
IList<T>
is invariant.
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:
IEnumerable<T>
is covariant because it is defined asIEnumerable<out T>
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....
Action<T>
is contravariant because it is defined asAction<in T>
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: