Lably
Skip to content

C Sharp 4.0

Version of the C# programming language

  • 10 min read
  • 1 chapter

Explore on Lably

ToursExplore Lably’s 3D tours

Features

The following new features were added in C# 4.0.

Dynamic member lookup

A new pseudo-type dynamic is introduced into the C# type system. It is treated 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 permitted without any type checking, and its resolution is postponed until run-time. This is known as duck typing. For example:

<span id="mwIA"></span><span class="w" id="mwIQ"> </span><span class="c1" id="mwIg">// Returns the value of Length property or field of any object</span> <span class="w" id="mwIw"> </span><span class="kt" id="mwJA">int</span><span class="w" id="mwJQ"> </span><span class="nf" id="mwJg">GetLength</span><span class="p" id="mwJw">(</span><span class="kt" id="mwKA">dynamic</span><span class="w" id="mwKQ"> </span><span class="n" id="mwKg">obj</span><span class="p" id="mwKw">)</span> <span class="w" id="mwLA"> </span><span class="p" id="mwLQ">{</span> <span class="w" id="mwLg"> </span><span class="k" id="mwLw">return</span><span class="w" id="mwMA"> </span><span class="n" id="mwMQ">obj</span><span class="p" id="mwMg">.</span><span class="n" id="mwMw">Length</span><span class="p" id="mwNA">;</span> <span class="w" id="mwNQ"> </span><span class="p" id="mwNg">}</span> <span class="w" id="mwNw"> </span> <span class="w" id="mwOA"> </span><span class="n" id="mwOQ">GetLength</span><span class="p" id="mwOg">(</span><span class="s" id="mwOw">"Hello, world"</span><span class="p" id="mwPA">);</span><span class="w" id="mwPQ"> </span><span class="c1" id="mwPg">// a string has a Length property,</span> <span class="w" id="mwPw"> </span><span class="n" id="mwQA">GetLength</span><span class="p" id="mwQQ">(</span><span class="k" id="mwQg">new</span><span class="w" id="mwQw"> </span><span class="kt" id="mwRA">int</span><span class="p" id="mwRQ">[]</span><span class="w" id="mwRg"> </span><span class="p" id="mwRw">{</span><span class="w" id="mwSA"> </span><span class="mi" id="mwSQ">1</span><span class="p" id="mwSg">,</span><span class="w" id="mwSw"> </span><span class="mi" id="mwTA">2</span><span class="p" id="mwTQ">,</span><span class="w" id="mwTg"> </span><span class="mi" id="mwTw">3</span><span class="w" id="mwUA"> </span><span class="p" id="mwUQ">});</span><span class="w" id="mwUg"> </span><span class="c1" id="mwUw">// and so does an array,</span> <span class="w" id="mwVA"> </span><span class="n" id="mwVQ">GetLength</span><span class="p" id="mwVg">(</span><span class="mi" id="mwVw">42</span><span class="p" id="mwWA">);</span><span class="w" id="mwWQ"> </span><span class="c1" id="mwWg">// but not an integer - an exception will be thrown in GetLength method at run-time</span>

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

<span id="mwXw"></span><span class="w" id="mwYA"> </span><span class="k" id="mwYQ">void</span><span class="w" id="mwYg"> </span><span class="nf" id="mwYw">Print</span><span class="p" id="mwZA">(</span><span class="kt" id="mwZQ">dynamic</span><span class="w" id="mwZg"> </span><span class="n" id="mwZw">obj</span><span class="p" id="mwaA">)</span> <span class="w" id="mwaQ"> </span><span class="p" id="mwag">{</span> <span class="w" id="mwaw"> </span><span class="n" id="mwbA">System</span><span class="p" id="mwbQ">.</span><span class="n" id="mwbg">Console</span><span class="p" id="mwbw">.</span><span class="n" id="mwcA">WriteLine</span><span class="p" id="mwcQ">(</span><span class="n" id="mwcg">obj</span><span class="p" id="mwcw">);</span><span class="w" id="mwdA"> </span><span class="c1" id="mwdQ">// which overload of WriteLine() to call is decided at run-time</span> <span class="w" id="mwdg"> </span><span class="p" id="mwdw">}</span> <span class="w" id="mweA"> </span><span class="n" id="mweQ">Print</span><span class="p" id="mweg">(</span><span class="mi" id="mwew">123</span><span class="p" id="mwfA">);</span><span class="w" id="mwfQ"> </span><span class="c1" id="mwfg">// ends up calling WriteLine(int)</span> <span class="w" id="mwfw"> </span><span class="n" id="mwgA">Print</span><span class="p" id="mwgQ">(</span><span class="s" id="mwgg">"abc"</span><span class="p" id="mwgw">);</span><span class="w" id="mwhA"> </span><span class="c1" id="mwhQ">// ends up calling WriteLine(string)</span>

Dynamic lookup is performed 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 consider the methods that are exposed on the declared compile-time type of the receiver. For example:

<span id="mwjg"></span><span class="k" id="mwjw">class</span><span class="w" id="mwkA"> </span><span class="nc" id="mwkQ">Base</span> <span class="p" id="mwkg">{</span> <span class="w" id="mwkw"> </span><span class="k" id="mwlA">void</span><span class="w" id="mwlQ"> </span><span class="nf" id="mwlg">Foo</span><span class="p" id="mwlw">(</span><span class="kt" id="mwmA">double</span><span class="w" id="mwmQ"> </span><span class="n" id="mwmg">x</span><span class="p" id="mwmw">);</span> <span class="p" id="mwnA">}</span> <span class="k" id="mwnQ">class</span><span class="w" id="mwng"> </span><span class="nc" id="mwnw">Derived</span><span class="w" id="mwoA"> </span><span class="p" id="mwoQ">:</span><span class="w" id="mwog"> </span><span class="n" id="mwow">Base</span> <span class="p" id="mwpA">{</span> <span class="w" id="mwpQ"> </span><span class="k" id="mwpg">void</span><span class="w" id="mwpw"> </span><span class="nf" id="mwqA">Foo</span><span class="p" id="mwqQ">(</span><span class="kt" id="mwqg">int</span><span class="w" id="mwqw"> </span><span class="n" id="mwrA">x</span><span class="p" id="mwrQ">);</span> <span class="p" id="mwrg">}</span> <span class="kt" id="mwrw">dynamic</span><span class="w" id="mwsA"> </span><span class="n" id="mwsQ">x</span><span class="w" id="mwsg"> </span><span class="o" id="mwsw">=</span><span class="w" id="mwtA"> </span><span class="mi" id="mwtQ">123</span><span class="p" id="mwtg">;</span> <span class="n" id="mwtw">Base</span><span class="w" id="mwuA"> </span><span class="n" id="mwuQ">b</span><span class="w" id="mwug"> </span><span class="o" id="mwuw">=</span><span class="w" id="mwvA"> </span><span class="k" id="mwvQ">new</span><span class="w" id="mwvg"> </span><span class="n" id="mwvw">Derived</span><span class="p" id="mwwA">();</span> <span class="n" id="mwwQ">b</span><span class="p" id="mwwg">.</span><span class="n" id="mwww">Foo</span><span class="p" id="mwxA">(</span><span class="n" id="mwxQ">x</span><span class="p" id="mwxg">);</span><span class="w" id="mwxw"> </span><span class="c1" id="mwyA">// picks Base.Foo(double) because b is of type Base, and Derived.Foo(int) is not exposed</span> <span class="kt" id="mwyQ">dynamic</span><span class="w" id="mwyg"> </span><span class="n" id="mwyw">b1</span><span class="w" id="mwzA"> </span><span class="o" id="mwzQ">=</span><span class="w" id="mwzg"> </span><span class="n" id="mwzw">b</span><span class="p" id="mw0A">;</span> <span class="n" id="mw0Q">b1</span><span class="p" id="mw0g">.</span><span class="n" id="mw0w">Foo</span><span class="p" id="mw1A">(</span><span class="n" id="mw1Q">x</span><span class="p" id="mw1g">);</span><span class="w" id="mw1w"> </span><span class="c1" id="mw2A">// picks Derived.Foo(int)</span>

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 GetLength 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.

Covariant and contravariant generic type parameters

Generic interfaces and delegates can have their type parameters marked as covariant or contravariant using keywords out and in respectively. These declarations are then respected for type conversions, both implicit and explicit, and both compile time and run time. For example, the existing interface IEnumerable<T> has been redefined as follows:

<span id="mw6A"></span><span class="k" id="mw6Q">interface</span><span class="w" id="mw6g"> </span><span class="n" id="mw6w">IEnumerable</span><span class="o" id="mw7A"><</span><span class="k" id="mw7Q">out</span><span class="w" id="mw7g"> </span><span class="n" id="mw7w">T</span><span class="o" id="mw8A">></span> <span class="p" id="mw8Q">{</span> <span class="w" id="mw8g"> </span><span class="n" id="mw8w">IEnumerator</span><span class="o" id="mw9A"><</span><span class="n" id="mw9Q">T</span><span class="o" id="mw9g">></span><span class="w" id="mw9w"> </span><span class="n" id="mw-A">GetEnumerator</span><span class="p" id="mw-Q">();</span> <span class="p" id="mw-g">}</span>

Therefore, any class that implements IEnumerable<Derived> for some class Derived is also considered to be compatible with IEnumerable<Base> for all classes and interfaces Base that Derived extends, directly or indirectly. In practice, it makes it possible to write code such as:

<span id="mwAQM"></span><span class="k" id="mwAQQ">void</span><span class="w" id="mwAQU"> </span><span class="nf" id="mwAQY">PrintAll</span><span class="p" id="mwAQc">(</span><span class="n" id="mwAQg">IEnumerable</span><span class="o" id="mwAQk"><</span><span class="kt" id="mwAQo">object</span><span class="o" id="mwAQs">></span><span class="w" id="mwAQw"> </span><span class="n" id="mwAQ0">objects</span><span class="p" id="mwAQ4">)</span> <span class="p" id="mwAQ8">{</span> <span class="w" id="mwARA"> </span><span class="k" id="mwARE">foreach</span><span class="w" id="mwARI"> </span><span class="p" id="mwARM">(</span><span class="kt" id="mwARQ">object</span><span class="w" id="mwARU"> </span><span class="n" id="mwARY">o</span><span class="w" id="mwARc"> </span><span class="k" id="mwARg">in</span><span class="w" id="mwARk"> </span><span class="n" id="mwARo">objects</span><span class="p" id="mwARs">)</span> <span class="w" id="mwARw"> </span><span class="p" id="mwAR0">{</span> <span class="w" id="mwAR4"> </span><span class="n" id="mwAR8">System</span><span class="p" id="mwASA">.</span><span class="n" id="mwASE">Console</span><span class="p" id="mwASI">.</span><span class="n" id="mwASM">WriteLine</span><span class="p" id="mwASQ">(</span><span class="n" id="mwASU">o</span><span class="p" id="mwASY">);</span> <span class="w" id="mwASc"> </span><span class="p" id="mwASg">}</span> <span class="p" id="mwASk">}</span> <span class="n" id="mwASo">IEnumerable</span><span class="o" id="mwASs"><</span><span class="kt" id="mwASw">string</span><span class="o" id="mwAS0">></span><span class="w" id="mwAS4"> </span><span class="n" id="mwAS8">strings</span><span class="w" id="mwATA"> </span><span class="o" id="mwATE">=</span><span class="w" id="mwATI"> </span><span class="k" id="mwATM">new</span><span class="w" id="mwATQ"> </span><span class="n" id="mwATU">List</span><span class="o" id="mwATY"><</span><span class="kt" id="mwATc">string</span><span class="o" id="mwATg">></span><span class="p" id="mwATk">();</span> <span class="n" id="mwATo">PrintAll</span><span class="p" id="mwATs">(</span><span class="n" id="mwATw">strings</span><span class="p" id="mwAT0">);</span><span class="w" id="mwAT4"> </span><span class="c1" id="mwAT8">// IEnumerable<string> is implicitly converted to IEnumerable<object></span>

For contravariance, the existing interface IComparer<T> has been redefined as follows:

<span id="mwAUQ"></span><span class="k" id="mwAUU">public</span><span class="w" id="mwAUY"> </span><span class="k" id="mwAUc">interface</span><span class="w" id="mwAUg"> </span><span class="n" id="mwAUk">IComparer</span><span class="o" id="mwAUo"><</span><span class="k" id="mwAUs">in</span><span class="w" id="mwAUw"> </span><span class="n" id="mwAU0">T</span><span class="o" id="mwAU4">></span> <span class="p" id="mwAU8">{</span> <span class="w" id="mwAVA"> </span><span class="kt" id="mwAVE">int</span><span class="w" id="mwAVI"> </span><span class="nf" id="mwAVM">Compare</span><span class="p" id="mwAVQ">(</span><span class="n" id="mwAVU">T</span><span class="w" id="mwAVY"> </span><span class="n" id="mwAVc">x</span><span class="p" id="mwAVg">,</span><span class="w" id="mwAVk"> </span><span class="n" id="mwAVo">T</span><span class="w" id="mwAVs"> </span><span class="n" id="mwAVw">y</span><span class="p" id="mwAV0">);</span> <span class="p" id="mwAV4">}</span>

Therefore, any class that implements IComparer<Base> for some class Base is also considered to be compatible with IComparer<Derived> for all classes and interfaces Derived that are extended from Base. It makes it possible to write code such as:

<span id="mwAWc"></span><span class="n" id="mwAWg">IComparer</span><span class="o" id="mwAWk"><</span><span class="kt" id="mwAWo">object</span><span class="o" id="mwAWs">></span><span class="w" id="mwAWw"> </span><span class="n" id="mwAW0">objectComparer</span><span class="w" id="mwAW4"> </span><span class="o" id="mwAW8">=</span><span class="w" id="mwAXA"> </span><span class="n" id="mwAXE">GetComparer</span><span class="p" id="mwAXI">();</span> <span class="n" id="mwAXM">IComparer</span><span class="o" id="mwAXQ"><</span><span class="kt" id="mwAXU">string</span><span class="o" id="mwAXY">></span><span class="w" id="mwAXc"> </span><span class="n" id="mwAXg">stringComparer</span><span class="w" id="mwAXk"> </span><span class="o" id="mwAXo">=</span><span class="w" id="mwAXs"> </span><span class="n" id="mwAXw">objectComparer</span><span class="p" id="mwAX0">;</span>

Optional ref keyword when using COM

The ref keyword for callers of methods is now optional when calling into methods supplied by COM interfaces. Given a COM method with the signature

<span id="mwAYQ"></span><span class="k" id="mwAYU">void</span><span class="w" id="mwAYY"> </span><span class="nf" id="mwAYc">Increment</span><span class="p" id="mwAYg">(</span><span class="k" id="mwAYk">ref</span><span class="w" id="mwAYo"> </span><span class="kt" id="mwAYs">int</span><span class="w" id="mwAYw"> </span><span class="n" id="mwAY0">x</span><span class="p" id="mwAY4">);</span>

the invocation can now be written as either

<span id="mwAZI"></span><span class="n" id="mwAZM">Increment</span><span class="p" id="mwAZQ">(</span><span class="mi" id="mwAZU">0</span><span class="p" id="mwAZY">);</span><span class="w" id="mwAZc"> </span><span class="c1" id="mwAZg">// no need for "ref" or a place holder variable any more</span>

or

<span id="mwAZw"></span><span class="kt" id="mwAZ0">int</span><span class="w" id="mwAZ4"> </span><span class="n" id="mwAZ8">x</span><span class="w" id="mwAaA"> </span><span class="o" id="mwAaE">=</span><span class="w" id="mwAaI"> </span><span class="mi" id="mwAaM">0</span><span class="p" id="mwAaQ">;</span> <span class="n" id="mwAaU">Increment</span><span class="p" id="mwAaY">(</span><span class="k" id="mwAac">ref</span><span class="w" id="mwAag"> </span><span class="n" id="mwAak">x</span><span class="p" id="mwAao">);</span>

Optional parameters and named arguments

C# 4.0 introduces optional parameters with default values as seen in Visual Basic and C++. For example:

<span id="mwAbE"></span><span class="k" id="mwAbI">void</span><span class="w" id="mwAbM"> </span><span class="nf" id="mwAbQ">Increment</span><span class="p" id="mwAbU">(</span><span class="k" id="mwAbY">ref</span><span class="w" id="mwAbc"> </span><span class="kt" id="mwAbg">int</span><span class="w" id="mwAbk"> </span><span class="n" id="mwAbo">x</span><span class="p" id="mwAbs">,</span><span class="w" id="mwAbw"> </span><span class="kt" id="mwAb0">int</span><span class="w" id="mwAb4"> </span><span class="n" id="mwAb8">dx</span><span class="w" id="mwAcA"> </span><span class="o" id="mwAcE">=</span><span class="w" id="mwAcI"> </span><span class="mi" id="mwAcM">1</span><span class="p" id="mwAcQ">)</span> <span class="p" id="mwAcU">{</span> <span class="w" id="mwAcY"> </span><span class="n" id="mwAcc">x</span><span class="w" id="mwAcg"> </span><span class="o" id="mwAck">+=</span><span class="w" id="mwAco"> </span><span class="n" id="mwAcs">dx</span><span class="p" id="mwAcw">;</span> <span class="p" id="mwAc0">}</span> <span class="kt" id="mwAc4">int</span><span class="w" id="mwAc8"> </span><span class="n" id="mwAdA">x</span><span class="w" id="mwAdE"> </span><span class="o" id="mwAdI">=</span><span class="w" id="mwAdM"> </span><span class="mi" id="mwAdQ">0</span><span class="p" id="mwAdU">;</span> <span class="n" id="mwAdY">Increment</span><span class="p" id="mwAdc">(</span><span class="k" id="mwAdg">ref</span><span class="w" id="mwAdk"> </span><span class="n" id="mwAdo">x</span><span class="p" id="mwAds">);</span><span class="w" id="mwAdw"> </span><span class="c1" id="mwAd0">// dx takes the default value of 1, after the method returns x == 1</span> <span class="n" id="mwAd4">Increment</span><span class="p" id="mwAd8">(</span><span class="k" id="mwAeA">ref</span><span class="w" id="mwAeE"> </span><span class="n" id="mwAeI">x</span><span class="p" id="mwAeM">,</span><span class="w" id="mwAeQ"> </span><span class="mi" id="mwAeU">2</span><span class="p" id="mwAeY">);</span><span class="w" id="mwAec"> </span><span class="c1" id="mwAeg">// dx takes the value 2, after the method returns x == 3</span>

In addition, to complement optional parameters, it is possible explicitly to specify parameter names in method calls, allowing the programmer selectively to pass any subset of optional parameters for a method. The only restriction is that named parameters must be placed after the unnamed parameters. Parameter names can be specified for both optional and required parameters, and can be used to improve readability or arbitrarily to reorder arguments in a call. For example:

<span id="mwAe0"></span><span class="n" id="mwAe4">Stream</span><span class="w" id="mwAe8"> </span><span class="nf" id="mwAfA">OpenFile</span><span class="p" id="mwAfE">(</span><span class="kt" id="mwAfI">string</span><span class="w" id="mwAfM"> </span><span class="n" id="mwAfQ">name</span><span class="p" id="mwAfU">,</span><span class="w" id="mwAfY"> </span><span class="n" id="mwAfc">FileMode</span><span class="w" id="mwAfg"> </span><span class="n" id="mwAfk">mode</span><span class="w" id="mwAfo"> </span><span class="o" id="mwAfs">=</span><span class="w" id="mwAfw"> </span><span class="n" id="mwAf0">FileMode</span><span class="p" id="mwAf4">.</span><span class="n" id="mwAf8">Open</span><span class="p" id="mwAgA">,</span><span class="w" id="mwAgE"> </span><span class="n" id="mwAgI">FileAccess</span><span class="w" id="mwAgM"> </span><span class="n" id="mwAgQ">access</span><span class="w" id="mwAgU"> </span><span class="o" id="mwAgY">=</span><span class="w" id="mwAgc"> </span><span class="n" id="mwAgg">FileAccess</span><span class="p" id="mwAgk">.</span><span class="n" id="mwAgo">Read</span><span class="p" id="mwAgs">)</span><span class="w" id="mwAgw"> </span><span class="p" id="mwAg0">{</span><span class="w" id="mwAg4"> </span><span class="p" id="mwAg8">...</span><span class="w" id="mwAhA"> </span><span class="p" id="mwAhE">}</span> <span class="n" id="mwAhI">OpenFile</span><span class="p" id="mwAhM">(</span><span class="s" id="mwAhQ">"file.txt"</span><span class="p" id="mwAhU">);</span><span class="w" id="mwAhY"> </span><span class="c1" id="mwAhc">// use default values for both "mode" and "access" </span> <span class="n" id="mwAhg">OpenFile</span><span class="p" id="mwAhk">(</span><span class="s" id="mwAho">"file.txt"</span><span class="p" id="mwAhs">,</span><span class="w" id="mwAhw"> </span><span class="n" id="mwAh0">mode</span><span class="p" id="mwAh4">:</span><span class="w" id="mwAh8"> </span><span class="n" id="mwAiA">FileMode</span><span class="p" id="mwAiE">.</span><span class="n" id="mwAiI">Create</span><span class="p" id="mwAiM">);</span><span class="w" id="mwAiQ"> </span><span class="c1" id="mwAiU">// use default value for "access"</span> <span class="n" id="mwAiY">OpenFile</span><span class="p" id="mwAic">(</span><span class="s" id="mwAig">"file.txt"</span><span class="p" id="mwAik">,</span><span class="w" id="mwAio"> </span><span class="n" id="mwAis">access</span><span class="p" id="mwAiw">:</span><span class="w" id="mwAi0"> </span><span class="n" id="mwAi4">FileAccess</span><span class="p" id="mwAi8">.</span><span class="n" id="mwAjA">Read</span><span class="p" id="mwAjE">);</span><span class="w" id="mwAjI"> </span><span class="c1" id="mwAjM">// use default value for "mode"</span> <span class="n" id="mwAjQ">OpenFile</span><span class="p" id="mwAjU">(</span><span class="n" id="mwAjY">name</span><span class="p" id="mwAjc">:</span><span class="w" id="mwAjg"> </span><span class="s" id="mwAjk">"file.txt"</span><span class="p" id="mwAjo">,</span><span class="w" id="mwAjs"> </span><span class="n" id="mwAjw">access</span><span class="p" id="mwAj0">:</span><span class="w" id="mwAj4"> </span><span class="n" id="mwAj8">FileAccess</span><span class="p" id="mwAkA">.</span><span class="n" id="mwAkE">Read</span><span class="p" id="mwAkI">,</span><span class="w" id="mwAkM"> </span><span class="n" id="mwAkQ">mode</span><span class="p" id="mwAkU">:</span><span class="w" id="mwAkY"> </span><span class="n" id="mwAkc">FileMode</span><span class="p" id="mwAkg">.</span><span class="n" id="mwAkk">Create</span><span class="p" id="mwAko">);</span><span class="w" id="mwAks"> </span><span class="c1" id="mwAkw">// name all parameters for extra readability, </span> <span class="w" id="mwAk0"> </span><span class="c1" id="mwAk4">// and use order different from method declaration</span>

Optional parameters make interoperating with COM easier. Previously, C# had to pass in every parameter in the method of the COM component, even those that are optional. For example:

<span id="mwAlI"></span><span class="kt" id="mwAlM">object</span><span class="w" id="mwAlQ"> </span><span class="n" id="mwAlU">fileName</span><span class="w" id="mwAlY"> </span><span class="o" id="mwAlc">=</span><span class="w" id="mwAlg"> </span><span class="s" id="mwAlk">"Test.docx"</span><span class="p" id="mwAlo">;</span> <span class="kt" id="mwAls">object</span><span class="w" id="mwAlw"> </span><span class="n" id="mwAl0">missing</span><span class="w" id="mwAl4"> </span><span class="o" id="mwAl8">=</span><span class="w" id="mwAmA"> </span><span class="n" id="mwAmE">System</span><span class="p" id="mwAmI">.</span><span class="n" id="mwAmM">Reflection</span><span class="p" id="mwAmQ">.</span><span class="n" id="mwAmU">Missing</span><span class="p" id="mwAmY">.</span><span class="n" id="mwAmc">Value</span><span class="p" id="mwAmg">;</span> <span class="n" id="mwAmk">doc</span><span class="p" id="mwAmo">.</span><span class="n" id="mwAms">SaveAs</span><span class="p" id="mwAmw">(</span><span class="k" id="mwAm0">ref</span><span class="w" id="mwAm4"> </span><span class="n" id="mwAm8">fileName</span><span class="p" id="mwAnA">,</span> <span class="w" id="mwAnE"> </span><span class="k" id="mwAnI">ref</span><span class="w" id="mwAnM"> </span><span class="n" id="mwAnQ">missing</span><span class="p" id="mwAnU">,</span><span class="w" id="mwAnY"> </span><span class="k" id="mwAnc">ref</span><span class="w" id="mwAng"> </span><span class="n" id="mwAnk">missing</span><span class="p" id="mwAno">,</span><span class="w" id="mwAns"> </span><span class="k" id="mwAnw">ref</span><span class="w" id="mwAn0"> </span><span class="n" id="mwAn4">missing</span><span class="p" id="mwAn8">,</span> <span class="w" id="mwAoA"> </span><span class="k" id="mwAoE">ref</span><span class="w" id="mwAoI"> </span><span class="n" id="mwAoM">missing</span><span class="p" id="mwAoQ">,</span><span class="w" id="mwAoU"> </span><span class="k" id="mwAoY">ref</span><span class="w" id="mwAoc"> </span><span class="n" id="mwAog">missing</span><span class="p" id="mwAok">,</span><span class="w" id="mwAoo"> </span><span class="k" id="mwAos">ref</span><span class="w" id="mwAow"> </span><span class="n" id="mwAo0">missing</span><span class="p" id="mwAo4">,</span> <span class="w" id="mwAo8"> </span><span class="k" id="mwApA">ref</span><span class="w" id="mwApE"> </span><span class="n" id="mwApI">missing</span><span class="p" id="mwApM">,</span><span class="w" id="mwApQ"> </span><span class="k" id="mwApU">ref</span><span class="w" id="mwApY"> </span><span class="n" id="mwApc">missing</span><span class="p" id="mwApg">,</span><span class="w" id="mwApk"> </span><span class="k" id="mwApo">ref</span><span class="w" id="mwAps"> </span><span class="n" id="mwApw">missing</span><span class="p" id="mwAp0">,</span> <span class="w" id="mwAp4"> </span><span class="k" id="mwAp8">ref</span><span class="w" id="mwAqA"> </span><span class="n" id="mwAqE">missing</span><span class="p" id="mwAqI">,</span><span class="w" id="mwAqM"> </span><span class="k" id="mwAqQ">ref</span><span class="w" id="mwAqU"> </span><span class="n" id="mwAqY">missing</span><span class="p" id="mwAqc">,</span><span class="w" id="mwAqg"> </span><span class="k" id="mwAqk">ref</span><span class="w" id="mwAqo"> </span><span class="n" id="mwAqs">missing</span><span class="p" id="mwAqw">,</span> <span class="w" id="mwAq0"> </span><span class="k" id="mwAq4">ref</span><span class="w" id="mwAq8"> </span><span class="n" id="mwArA">missing</span><span class="p" id="mwArE">,</span><span class="w" id="mwArI"> </span><span class="k" id="mwArM">ref</span><span class="w" id="mwArQ"> </span><span class="n" id="mwArU">missing</span><span class="p" id="mwArY">,</span><span class="w" id="mwArc"> </span><span class="k" id="mwArg">ref</span><span class="w" id="mwArk"> </span><span class="n" id="mwAro">missing</span><span class="p" id="mwArs">);</span>

With support for optional parameters, the code can be shortened as

<span id="mwAr8"></span><span class="n" id="mwAsA">doc</span><span class="p" id="mwAsE">.</span><span class="n" id="mwAsI">SaveAs</span><span class="p" id="mwAsM">(</span><span class="k" id="mwAsQ">ref</span><span class="w" id="mwAsU"> </span><span class="n" id="mwAsY">fileName</span><span class="p" id="mwAsc">);</span>

Which, due to the now optional ref keyword when using COM, can further be shortened as

<span id="mwAsw"></span><span class="n" id="mwAs0">doc</span><span class="p" id="mwAs4">.</span><span class="n" id="mwAs8">SaveAs</span><span class="p" id="mwAtA">(</span><span class="n" id="mwAtE">fileName</span><span class="p" id="mwAtI">);</span>

Indexed properties

Indexed properties (and default properties) of COM objects are now recognized, but C# objects still do not support them.

More in Computing and communication