Friday, March 23, 2012

Dynamic member lookup in C# 4.0

A new pseudo-type dynamic is presented into the C# type system. It is considered as System.Object, but in addition, any member access (method call, field, property, or indexer access, or a delegate invocation) or application of an operator on a value of such type is allowed without any type checking, and its tenacity is postponed until run-time. This is known as Duck typing

// Returns the value of Length property or field of any object which supports the length
int GetLengthOf(dynamic obj)
{
return obj.Length;
}

Now, consider followings

// a string has a Length property, So, It’s a valid
// returns 34 including white spaces
GetLengthOf("This time my Return is Huge! - DON");

// an array has a Length property, So, It’s a valid
// returns 3, holding 3 items in an array
GetLengthOf(new int[] { 1, 2, 3 });

// but not an integer - an exception will be thrown here at run-time
// returns exception as 'int' does not contain a definition for 'Length'
GetLengthOf(42); 

Dynamic method calls are triggered by a value of type "dynamic" as any implicit or explicit parameter (and not just a receiver). For example:

void PrintThis(dynamic obj)
{
// which overload of Write() to call is decided at run-time
Response.Write(obj);
}
 
PrintThis(3*6);   // ends up calling Write(int)
PrintThis("Don retruns"); // ends up calling Write(string)

Dynamic lookup is achieved using three distinct mechanisms: COM IDispatch for COM objects, IDynamicMetaObjectProvider DLR interface for objects implementing that interface, and reflection for all other objects. Any C# class can therefore intercept dynamic calls on its instances by implementing IDynamicMetaObjectProvider.

In case of dynamic method and indexer calls, overload resolution happens at run-time according to the actual types of the values passed as arguments, but otherwise according to the usual C# overloading resolution rules. Furthermore, in cases where the receiver in a dynamic call is not itself dynamic, run-time overload resolution will only reflect the methods that are exposed on the declared compile-time type of the receiver. . For example:

class BaseClass
{
  void Don(double me);
}

class DerivedClass : BaseClass
{
  void Don(int me);
}

dynamic me = 55;
BaseClass b = new DerivedClass();
// picks BaseClass.Don(double) because b is of type Base, and DerivedClass.Don(int) is not exposed
b.Don(me);
  
dynamic myself = b;
// picks DerivedClass.Don(int)
myself.Don(me); 

Any value returned from a dynamic member access is itself of type dynamic. Values of type dynamic are implicitly convertible both from and to any other type. In the code sample above, this permits GetLengthOf function to treat the value returned by a call to Length as an integer without any explicit cast. At run-time, the actual value will be converted to the requested type.

No comments:

Post a Comment