Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 26

March 31st 2010

C# 4.0 Language Features

Alexandru Ghiondea
Software Developer Engineer in Test
C# Compiler
Ghiondea.Alexandru@microsoft.com
March 31st 2010

C# 4.0 Language

Alexandru Ghiondea
Software Developer Engineer in Test
C# Compiler
Ghiondea.Alexandru@microsoft.com
The Evolution of C#

C# 4.0
Dynamic
Programming

C# 3.0
Language Integrated
Query

C# 2.0
Generics
C# 1.0

Managed Code
C# 4.0 Language Innovations
− Dynamically Typed Objects
− Optional and Named Parameters
− Improved COM Interoperability
− Co- and Contra-variance
.NET Dynamic Programming
IronPython IronRuby C# VB.NET Others…

Dynamic Language Runtime


Expression Trees Dynamic Dispatch Call Site Caching

Object JavaScript Python Ruby COM


Binder Binder Binder Binder Binder
Dynamically Typed Objects
Calculator calc = GetCalculator();
int sum = calc.Add(10, 20);

.NET object
object calc = GetCalculator();
Type calcType = calc.GetType();
object res = calcType.InvokeMember("Add",
BindingFlags.InvokeMethod, null,
new object[] { 10, 20 }); Dynamic Language object
int sum = Convert.ToInt32(res); ScriptObject calc = GetCalculator();
object res = calc.Invoke("Add", 10, 20);
int sum = Convert.ToInt32(res);
Statically typed
to be dynamic dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);

Dynamic Dynamic method


conversion invocation
Under the cover dynamic
int sum
calc = GetCalculator();
= calc.Add(10, 20);

− dynamic is a new type only in the compiler


− Encoded in IL as object + DynamicAttribute
− NO dynamic type in the CLR
− There is an implicit conversion from dynamic to any type

− Operations on a dynamic variable become CallSites,


objects “interpreted” by the DLR
− Member selection deferred to run-time
− We cache the result of the bindings
− The return type of a dynamic operation is dynamic

− We support all types of operations on dynamic


− Method call, property access, indexer access, operators,
conversions
Under the cover dynamic i = 3;
Math.Abs(i);

− For binding calls to .NET types we have a runtime


C# binder
− Does overload resolution using runtime types for
dynamic arguments

− Overload resolution changed to accommodate


dynamic method calls
− Dynamic arguments are treated as wildcards for
overload resolution
Under the cover
− When does the compiler dispatch
dynamically?
− If the receiver of the call is dynamic OR
− If any of the arguments to the call are typed
dynamic

− We can dynamically dispatch to static


methods 
Under the cover
dynamic d = new DynamicObject();
d.Foo();

− You can now write your own object that


does dynamic dispatch
− Just implement IDynamicObject

− The C# runtime binder can function as


a fallback for calls to dynamic objects
− If your object is “hybrid” and some of the
methods are dynamically dispatched and
some are regular methods
− The C# semantics will be applied if the
object cannot itself resolve a call
IDynamicObject
public
public abstract
abstract class
class DynamicObject
DynamicObject :
: IDynamicObject
IDynamicObject
{
{
public
public virtual
virtual object
object GetMember(GetMemberBinder
GetMember(GetMemberBinder info);
info);
public
public virtual
virtual object
object SetMember(SetMemberBinder
SetMember(SetMemberBinder info,
info, object
object value);
value);
public
public virtual
virtual object
object DeleteMember(DeleteMemberBinder
DeleteMember(DeleteMemberBinder info);
info);
 
 
public
public virtual
virtual object
object UnaryOperation(UnaryOperationBinder
UnaryOperation(UnaryOperationBinder info);
info);
public
public virtual object BinaryOperation(BinaryOperationBinder info,
virtual object BinaryOperation(BinaryOperationBinder info, object
object arg);
arg);
public virtual object Convert(ConvertBinder info);
public virtual object Convert(ConvertBinder info);
 
 
public
public virtual
virtual object
object Invoke(InvokeBinder
Invoke(InvokeBinder info,
info, object[]
object[] args);
args);
public
public virtual object InvokeMember(InvokeMemberBinder info, object[]
virtual object InvokeMember(InvokeMemberBinder info, object[] args);
args);
public
public virtual object CreateInstance(CreateInstanceBinder info, object[] args);
virtual object CreateInstance(CreateInstanceBinder info, object[] args);
 
 
public
public virtual
virtual object
object GetIndex(GetIndexBinder
GetIndex(GetIndexBinder info,
info, object[]
object[] indices);
indices);
public
public virtual
virtual object
object SetIndex(SetIndexBinder
SetIndex(SetIndexBinder info,
info, object[]
object[] indices,
indices, object
object value);
value);
public virtual object DeleteIndex(DeleteIndexBinder info, object[] indices);
public virtual object DeleteIndex(DeleteIndexBinder info, object[] indices);
 
 
public
public MetaObject
MetaObject IDynamicObject.GetMetaObject();
IDynamicObject.GetMetaObject();
}
}
DEMO
Implementing IDynamicObject
Improved COM Interoperability
− Automatic object  dynamic mapping
− Optional and named parameters
− Optional “ref” modifier
− Interop type embedding (“No PIA”)
− Indexed properties
object -> dynamic mapping
We need to cast

((Excel.Range)xl.Cells[1,1]).Value2 = “ID”;

xl.Cells[1,1].Value2 = “ID”;

− When the return type of a COM call is object you are


forced to cast to a known type
− Making the code harder to understand

− If the return type is dynamic, you can continue to “dot”


on the return type
− If you typed something wrong the compiler won’t tell you
Optional and named parameters
xlChart.ChartWizard(cellRange.CurrentRegion,
    Constants.xl3DBar, Type.Missing, Excel.XlRowCol.xlColumns,
1, 2, false, xlSheet.Name, Type.Missing,
Type.Missing, Type.Missing);

Non-optional must
be specified

xlChart.ChartWizard(cellRange.CurrentRegion, Constants.xl3DBar,
PlotBy: Excel.XlRowCol.xlColumns,
SeriesLabels: 2,
CategoryLabels: 1,
HasLegend: false,
Title: xlSheet.Name);

Named arguments Arguments


can appear in any evaluated in order
order written
Optional and named parameters
public StreamReader OpenTextFile(
Optional parameters
string path,
Encoding encoding
encoding,= null,
bool detectEncoding
detectEncoding,= true,
int bufferSize
bufferSize);
= 1024);

OpenTextFile("foo.txt”); Named argument

OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 4096);


Optional “ref” modifier

object fileName = "Test.docx";


object missing = System.Reflection.Missing.Value;

doc.SaveAs(ref fileName,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing);

doc.SaveAs("Test.docx");
Under the cover
− The default value for a parameter is
encoded with a DefaultParameterValue
attribute
− The compiler inserts that value if a value is
not specified for that parameter
− If a default value is not specified we will use
default(type)
− For COM, the compiler will pass in Type.Missing

− The compiler will rearrange the specified


named parameters and then apply
overload resolution
Under the cover
− You can override methods that declare optional
parameters
− The value of the parameter comes from the static
type you used to call the method

− You can rename a parameter in an override


− The compiler will use the name found in the static
type you used to call the method

− “omit ref” only works for COM objects


− The compiler creates a variable to store the value
you specified
− And passes the created variable “by ref” to COM
Co- and Contra-variance
.NET arrays are
string[] strings = GetStringArray(); co-variant
Process(strings);

void Process(object[] objects) { … } …but not safely


objects[0] = "Hello"; // Ok co-variant
objects[1] = new Button(); // Exception!
}
Until now, C#
generics have
List<string> strings = GetStringList(); been invariant
Process(strings);
C# 4.0 supports
void Process(IEnumerable<object> objects) { … } safe co- and
// IEnumerable<T> is read-only and contra-variance
// therefore safely co-variant
}
Safe Co- and Contra-variance
public interface IEnumerable<out
IEnumerable<T> T> out = Co-variant
{ Output positions only
IEnumerator<T> GetEnumerator();
}
Can be treated as
public interface IEnumerator<out
IEnumerator<T> T>
less derived
{
T Current { get; } IEnumerable<string> strings = GetStrings();
bool MoveNext(); IEnumerable<object> objects = strings;
}
in = Contra-variant
Input positions only
public interface IComparer<T>
IComparer<in T>
{ Can be treated as
int Compare(T x, T y); more derived
}
IComparer<object> objComp = GetComparer();
IComparer<string> strComp = objComp;
Variance in C# 4.0
− Supported for interface and delegate
types
− “Statically checked definition-site
variance”
− Value types are always invariant
− IEnumerable<int> is not
IEnumerable<object>
− Similar to existing rules for arrays
− ref and out parameters need invariant
type
Summary
− Dynamic
− Named and Optional
− Omit Ref
− No PIA
− Indexed properties
− Co/Contra variance
Additional Resources
− C# 4.0 Samples and Whitepaper
− http://code.msdn.microsoft.com/csharpfuture

− Visual C# Developer Center


− http://csharp.net
− C# team member’s blogs
− http://blogs.msdn.com/ericlippert/
− http://blogs.msdn.com/cburrows/
− http://blogs.msdn.com/samng/
− http://blogs.msdn.com/sreekarc/
− http://blogs.msdn.com/mattwar/
− http://blogs.msdn.com/ed_maurer/
− http://blogs.msdn.com/davsterl/
− http://blogs.msdn.com/alexghi
Pop quiz! 
class Base {
    public virtual void Foo(int x = 4, int y = 5) {
        Console.WriteLine("x:{0}, y:{1}", x, y);
    }
}

class Derived : Base {


    public override void Foo(int y = 4, int x = 5) {
        Console.WriteLine("x:{0}, y:{1}", x, y);
    }
}
Output:
class Program { a) x:4, y:5
    static void Main(string[] args) { b) x:5, y:4
        Base b = new Derived(); c) x:4, y:4
        b.Foo(x: 4, y: 5); d) x:5, y:5
    } e) None of the above
}
Q&A

You might also like