Conversions - C# language specification (original) (raw)

10.1 General

A conversion causes an expression to be converted to, or treated as being of, a particular type; in the former case a conversion may involve a change in representation. Conversions can be implicit or explicit, and this determines whether an explicit cast is required.

Example: For instance, the conversion from type int to type long is implicit, so expressions of type int can implicitly be treated as type long. The opposite conversion, from type long to type int, is explicit and so an explicit cast is required.

int a = 123;
long b = a;      // implicit conversion from int to long
int c = (int) b; // explicit conversion from long to int

end example

Some conversions are defined by the language. Programs may also define their own conversions (§10.5).

Some conversions in the language are defined from expressions to types, others from types to types. A conversion from a type applies to all expressions that have that type.

Example:

enum Color { Red, Blue, Green }

// The expression 0 converts implicitly to enum types
Color c0 = 0;

// Other int expressions need explicit conversion
Color c1 = (Color)1;

// Conversion from null expression (no type) to string
string x = null;

// Conversion from lambda expression to delegate type
Func<int, int> square = x => x * x;

end example

10.2 Implicit conversions

10.2.1 General

The following conversions are classified as implicit conversions:

Implicit conversions can occur in a variety of situations, including function member invocations (§12.6.6), cast expressions (§12.9.7), and assignments (§12.21).

The pre-defined implicit conversions always succeed and never cause exceptions to be thrown.

Note: Properly designed user-defined implicit conversions should exhibit these characteristics as well. end note

For the purposes of conversion, the types object and dynamic are identity convertible (§10.2.2).

However, dynamic conversions (§10.2.10) apply only to expressions of type dynamic (§8.2.4).

10.2.2 Identity conversion

An identity conversion converts from any type to the same type or a type that is equivalent at runtime. One reason this conversion exists is so that a type T or an expression of type T can be said to be convertible to T itself. The following identity conversions exist:

Example: The following illustrates the recursive nature of the third rule:

(int a , string b) t1 = (1, "two");
(int c, string d) t2 = (3, "four");

// Identity conversions exist between
// the types of t1, t2, and t3.
var t3 = (5, "six");
t3 = t2;
t2 = t1;

var t4 = (t1, 7);
var t5 = (t2, 8);

// Identity conversions exist between
// the types of t4, t5, and t6.
var t6 =((8, "eight"), 9);
t6 = t5;
t5 = t4;

The types of tuples t1, t2 and t3 all have two elements: an int followed by a string. Tuple element types may themselves by tuples, as in t4, t5, and t6. An identity conversion exists between each pair of corresponding element types, including nested tuples, therefore an identity conversion exists between the types of tuples t4, t5, and t6.

end example

All identity conversions are symmetric. If an identity conversion exists from T₁ to T₂, then an identity conversion exists from T₂ to T₁. Two types are identity convertible when an identity conversion exists between two types.

In most cases, an identity conversion has no effect at runtime. However, since floating point operations may be performed at higher precision than prescribed by their type (§8.3.7), assignment of their results may result in a loss of precision, and explicit casts are guaranteed to reduce precision to what is prescribed by the type (§12.9.7).

10.2.3 Implicit numeric conversions

The implicit numeric conversions are:

Conversions from int, uint, long or ulong to float and from long or ulong to double may cause a loss of precision, but will never cause a loss of magnitude. The other implicit numeric conversions never lose any information.

There are no predefined implicit conversions to the char type, so values of the other integral types do not automatically convert to the char type.

10.2.4 Implicit enumeration conversions

An implicit enumeration conversion permits a constant_expression (§12.23) with any integer type and the value zero to be converted to any enum_type and to any nullable_value_type whose underlying type is an enum_type. In the latter case the conversion is evaluated by converting to the underlying enum_type and wrapping the result (§8.3.12).

10.2.5 Implicit interpolated string conversions

An implicit interpolated string conversion permits an interpolated_string_expression (§12.8.3) to be converted to System.IFormattable or System.FormattableString (which implements System.IFormattable). When this conversion is applied, a string value is not composed from the interpolated string. Instead an instance of System.FormattableString is created, as further described in §12.8.3.

10.2.6 Implicit nullable conversions

The implicit nullable conversions are those nullable conversions (§10.6.1) derived from implicit predefined conversions.

10.2.7 Null literal conversions

An implicit conversion exists from the null literal to any reference type or nullable value type. This conversion produces a null reference if the target type is a reference type, or the null value (§8.3.12) of the given nullable value type.

10.2.8 Implicit reference conversions

The implicit reference conversions are:

The implicit reference conversions are those conversions between _reference_type_s that can be proven to always succeed, and therefore require no checks at run-time.

Reference conversions, implicit or explicit, never change the referential identity of the object being converted.

Note: In other words, while a reference conversion can change the type of the reference, it never changes the type or value of the object being referred to. end note

10.2.9 Boxing conversions

A boxing conversion permits a value_type to be implicitly converted to a reference_type. The following boxing conversions exist:

Boxing a value of a non-nullable-value-type consists of allocating an object instance and copying the value into that instance.

Boxing a value of a nullable_value_type produces a null reference if it is the null value (HasValue is false), or the result of unwrapping and boxing the underlying value otherwise.

Note: The process of boxing may be imagined in terms of the existence of a boxing class for every value type. For example, consider a struct S implementing an interface I, with a boxing class called S_Boxing.

interface I
{
   void M();
}

struct S : I
{
   public void M() { ... }
}

sealed class S_Boxing : I
{
   S value;

   public S_Boxing(S value)
   {
       this.value = value;
   }

   public void M()
   {
       value.M();
   }
}

Boxing a value v of type S now consists of executing the expression new S_Boxing(v) and returning the resulting instance as a value of the target type of the conversion. Thus, the statements

S s = new S();
object box = s;

can be thought of as similar to:

S s = new S();
object box = new S_Boxing(s);

The imagined boxing type described above does not actually exist. Instead, a boxed value of type S has the runtime type S, and a runtime type check using the is operator with a value type as the right operand tests whether the left operand is a boxed version of the right operand. For example,

int i = 123;
object box = i;
if (box is int)
{
   Console.Write("Box contains an int");
}

will output the following:

Box contains an int

A boxing conversion implies making a copy of the value being boxed. This is different from a conversion of a reference_type to type object, in which the value continues to reference the same instance and simply is regarded as the less derived type object. For example, the following

struct Point
{
   public int x, y;

   public Point(int x, int y)
   {
       this.x = x;
       this.y = y;
   }
}

class A
{
   void M() 
   {
       Point p = new Point(10, 10);
       object box = p;
       p.x = 20;
       Console.Write(((Point)box).x);
   }
}

will output the value 10 on the console because the implicit boxing operation that occurs in the assignment of p to box causes the value of p to be copied. Had Point been declared a class instead, the value 20 would be output because p and box would reference the same instance.

The analogy of a boxing class should not be used as more than a helpful tool for picturing how boxing works conceptually. There are numerous subtle differences between the behavior described by this specification and the behavior that would result from boxing being implemented in precisely this manner.

end note

10.2.10 Implicit dynamic conversions

An implicit dynamic conversion exists from an expression of type dynamic to any type T. The conversion is dynamically bound §12.3.3, which means that an implicit conversion will be sought at run-time from the run-time type of the expression to T. If no conversion is found, a run-time exception is thrown.

This implicit conversion seemingly violates the advice in the beginning of §10.2 that an implicit conversion should never cause an exception. However, it is not the conversion itself, but the finding of the conversion that causes the exception. The risk of run-time exceptions is inherent in the use of dynamic binding. If dynamic binding of the conversion is not desired, the expression can be first converted to object, and then to the desired type.

Example: The following illustrates implicit dynamic conversions:

object o = "object";
dynamic d = "dynamic";
string s1 = o;         // Fails at compile-time – no conversion exists
string s2 = d;         // Compiles and succeeds at run-time
int i = d;             // Compiles but fails at run-time – no conversion exists

The assignments to s2 and i both employ implicit dynamic conversions, where the binding of the operations is suspended until run-time. At run-time, implicit conversions are sought from the run-time type of d(string) to the target type. A conversion is found to string but not to int.

end example

10.2.11 Implicit constant expression conversions

An implicit constant expression conversion permits the following conversions:

10.2.12 Implicit conversions involving type parameters

For a type_parameter T that is known to be a reference type (§15.2.5), the following implicit reference conversions (§10.2.8) exist:

For a type_parameter T that is not known to be a reference type §15.2.5, the following conversions involving T are considered to be boxing conversions (§10.2.9) at compile-time. At run-time, if T is a value type, the conversion is executed as a boxing conversion. At run-time, if T is a reference type, the conversion is executed as an implicit reference conversion or identity conversion.

For a type_parameter T that is not known to be a reference type, there is an implicit conversion from T to a type parameter U provided T depends on U. At run-time, if T is a value type and U is a reference type, the conversion is executed as a boxing conversion. At run-time, if both T and U are value types, then T and U are necessarily the same type and no conversion is performed. At run-time, if T is a reference type, then U is necessarily also a reference type and the conversion is executed as an implicit reference conversion or identity conversion (§15.2.5).

The following further implicit conversions exist for a given type parameter T:

In all cases, the rules ensure that a conversion is executed as a boxing conversion if and only if at run-time the conversion is from a value type to a reference type.

10.2.13 Implicit tuple conversions

An implicit conversion exists from a tuple expression E to a tuple type T if E has the same arity as T and an implicit conversion exists from each element in E to the corresponding element type in T. The conversion is performed by creating an instance of T’s corresponding System.ValueTuple<...> type, and initializing each of its fields in order from left to right by evaluating the corresponding tuple element expression of E, converting it to the corresponding element type of T using the implicit conversion found, and initializing the field with the result.

If an element name in the tuple expression does not match a corresponding element name in the tuple type, a warning shall be issued.

Example:

(int, string) t1 = (1, "One");
(byte, string) t2 = (2, null);
(int, string) t3 = (null, null);        // Error: No conversion
(int i, string s) t4 = (i: 4, "Four");
(int i, string) t5 = (x: 5, s: "Five"); // Warning: Names are ignored

The declarations of t1, t2, t4 and t5 are all valid, since implicit conversions exist from the element expressions to the corresponding element types. The declaration of t3 is invalid, because there is no conversion from null to int. The declaration of t5 causes a warning because the element names in the tuple expression differs from those in the tuple type.

end example

10.2.14 User-defined implicit conversions

A user-defined implicit conversion consists of an optional standard implicit conversion, followed by execution of a user-defined implicit conversion operator, followed by another optional standard implicit conversion. The exact rules for evaluating user-defined implicit conversions are described in §10.5.4.

10.2.15 Anonymous function conversions and method group conversions

Anonymous functions and method groups do not have types in and of themselves, but they may be implicitly converted to delegate types. Additionally, some lambda expressions may be implicitly converted to expression tree types. Anonymous function conversions are described in more detail in §10.7 and method group conversions in §10.8.

10.2.16 Default literal conversions

An implicit conversion exists from a default_literal (§12.8.21) to any type. This conversion produces the default value (§9.3) of the inferred type.

10.2.17 Implicit throw conversions

While throw expressions do not have a type, they may be implicitly converted to any type.

10.3 Explicit conversions

10.3.1 General

The following conversions are classified as explicit conversions:

Explicit conversions can occur in cast expressions (§12.9.7).

The set of explicit conversions includes all implicit conversions.

Note: This, for example, allows an explicit cast to be used when an implicit identity conversion exists, in order to force the selection of a particular method overload. end note

The explicit conversions that are not implicit conversions are conversions that cannot be proven always to succeed, conversions that are known possibly to lose information, and conversions across domains of types sufficiently different to merit explicit notation.

10.3.2 Explicit numeric conversions

The explicit numeric conversions are the conversions from a numeric_type to another numeric_type for which an implicit numeric conversion (§10.2.3) does not already exist:

Because the explicit conversions include all implicit and explicit numeric conversions, it is always possible to convert from any numeric_type to any other numeric_type using a cast expression (§12.9.7).

The explicit numeric conversions possibly lose information or possibly cause exceptions to be thrown. An explicit numeric conversion is processed as follows:

Note: The decimal type is not required to support infinities or NaN values but may do so; its range may be smaller than the range of float and double, but is not guaranteed to be. For decimal representations without infinities or NaN values, and with a range smaller than float, the result of a conversion from decimal to either float or double will never be infinity or NaN. end note

10.3.3 Explicit enumeration conversions

The explicit enumeration conversions are:

An explicit enumeration conversion between two types is processed by treating any participating enum_type as the underlying type of that enum_type, and then performing an implicit or explicit numeric conversion between the resulting types.

Example: Given an enum_type E with an underlying type of int, a conversion from E to byte is processed as an explicit numeric conversion (§10.3.2) from int to byte, and a conversion from byte to E is processed as an implicit numeric conversion (§10.2.3) from byte to int. end example

10.3.4 Explicit nullable conversions

The explicit nullable conversions are those nullable conversions (§10.6.1) derived from explicit and implicit predefined conversions.

10.3.5 Explicit reference conversions

The explicit reference conversions are:

The explicit reference conversions are those conversions between _reference_type_s that require run-time checks to ensure they are correct.

For an explicit reference conversion to succeed at run-time, the value of the source operand shall be null, or the type of the object referenced by the source operand shall be a type that can be converted to the destination type by an implicit reference conversion (§10.2.8). If an explicit reference conversion fails, a System.InvalidCastException is thrown.

Note: Reference conversions, implicit or explicit, never change the value of the reference itself (§8.2.1), only its type; neither does it change the type or value of the object being referenced. end note

10.3.6 Explicit tuple conversions

An explicit conversion exists from a tuple expression E to a tuple type T if E has the same arity as T and an implicit or explicit conversion exists from each element in E to the corresponding element type in T. The conversion is performed by creating an instance of T’s corresponding System.ValueTuple<...> type, and initializing each of its fields in order from left to right by evaluating the corresponding tuple element expression of E, converting it to the corresponding element type of T using the explicit conversion found, and initializing the field with the result.

10.3.7 Unboxing conversions

An unboxing conversion permits a reference_type to be explicitly converted to a value_type. The following unboxing conversions exist:

An unboxing operation to a non_nullable_value_type consists of first checking that the object instance is a boxed value of the given non_nullable_value_type, and then copying the value out of the instance.

Unboxing to a nullable_value_type produces the null value of the nullable_value_type if the source operand is null, or the wrapped result of unboxing the object instance to the underlying type of the nullable_value_type otherwise.

Note: Referring to the imaginary boxing class described in §10.2.9, an unboxing conversion of an object box to a value_type S consists of executing the expression ((S_Boxing)box).value. Thus, the statements

object box = new S();
S s = (S)box;

conceptually correspond to

object box = new S_Boxing(new S());
S s = ((S_Boxing)box).value;

end note

For an unboxing conversion to a given non_nullable_value_type to succeed at run-time, the value of the source operand shall be a reference to a boxed value of that non_nullable_value_type. If the source operand is null a System.NullReferenceException is thrown. If the source operand is a reference to an incompatible object, a System.InvalidCastException is thrown.

For an unboxing conversion to a given nullable_value_type to succeed at run-time, the value of the source operand shall be either null or a reference to a boxed value of the underlying non_nullable_value_type of the nullable_value_type. If the source operand is a reference to an incompatible object, a System.InvalidCastException is thrown.

10.3.8 Explicit conversions involving type parameters

For a type_parameter T that is known to be a reference type (§15.2.5), the following explicit reference conversions (§10.3.5) exist:

For a type_parameter T that is not known to be a reference type (§15.2.5), the following conversions involving T are considered to be unboxing conversions (§10.3.7) at compile-time. At run-time, if T is a value type, the conversion is executed as an unboxing conversion. At run-time, if T is a reference type, the conversion is executed as an explicit reference conversion or identity conversion.

For a type_parameter T that is not known to be a reference type (§15.2.5), the following explicit conversions exist:

In all cases, the rules ensure that a conversion is executed as an unboxing conversion if and only if at run-time the conversion is from a reference type to a value type.

The above rules do not permit a direct explicit conversion from an unconstrained type parameter to a non-interface type, which might be surprising. The reason for this rule is to prevent confusion and make the semantics of such conversions clear.

Example: Consider the following declaration:

class X<T>
{
   public static long F(T t)
   {
       return (long)t;         // Error
   }
}

If the direct explicit conversion of t to long were permitted, one might easily expect that X<int>.F(7) would return 7L. However, it would not, because the standard numeric conversions are only considered when the types are known to be numeric at binding-time. In order to make the semantics clear, the above example must instead be written:

class X<T>
{
   public static long F(T t)
   {
       return (long)(object)t;         // Ok, but will only work when T is long
   }
}

This code will now compile but executing X<int>.F(7) would then throw an exception at run-time, since a boxed int cannot be converted directly to a long.

end example

10.3.9 User-defined explicit conversions

A user-defined explicit conversion consists of an optional standard explicit conversion, followed by execution of a user-defined implicit or explicit conversion operator, followed by another optional standard explicit conversion. The exact rules for evaluating user-defined explicit conversions are described in §10.5.5.

10.4 Standard conversions

10.4.1 General

The standard conversions are those pre-defined conversions that can occur as part of a user-defined conversion.

10.4.2 Standard implicit conversions

The following implicit conversions are classified as standard implicit conversions:

The standard implicit conversions specifically exclude user-defined implicit conversions.

10.4.3 Standard explicit conversions

The standard explicit conversions are all standard implicit conversions plus the subset of the explicit conversions for which an opposite standard implicit conversion exists.

Note: In other words, if a standard implicit conversion exists from a type A to a type B, then a standard explicit conversion exists from type A to type B and from type B to type A. end note

10.5 User-defined conversions

10.5.1 General

C# allows the pre-defined implicit and explicit conversions to be augmented by user-defined conversions. User-defined conversions are introduced by declaring conversion operators (§15.10.4) in class and struct types.

10.5.2 Permitted user-defined conversions

C# permits only certain user-defined conversions to be declared. In particular, it is not possible to redefine an already existing implicit or explicit conversion.

For a given source type S and target type T, if S or T are nullable value types, let S₀ and T₀ refer to their underlying types, otherwise S₀ and T₀ are equal to S and T respectively. A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true:

The restrictions that apply to user-defined conversions are specified in §15.10.4.

10.5.3 Evaluation of user-defined conversions

A user-defined conversion converts a source expression, which may have a source type, to another type, called the target type. Evaluation of a user-defined conversion centers on finding the most-specific user-defined conversion operator for the source expression and target type. This determination is broken into several steps:

Once a most-specific user-defined conversion operator has been identified, the actual execution of the user-defined conversion involves up to three steps:

Evaluation of a user-defined conversion never involves more than one user-defined or lifted conversion operator. In other words, a conversion from type S to type T will never first execute a user-defined conversion from S to X and then execute a user-defined conversion from X to T.

10.5.4 User-defined implicit conversions

A user-defined implicit conversion from an expression E to a type T is processed as follows:

A user-defined implicit conversion from a type S to a type T exists if a user-defined implicit conversion exists from a variable of type S to T.

10.5.5 User-defined explicit conversions

A user-defined explicit conversion from an expression E to a type T is processed as follows:

A user-defined explicit conversion from a type S to a type T exists if a user-defined explicit conversion exists from a variable of type S to T.

10.6 Conversions involving nullable types

10.6.1 Nullable Conversions

Nullable conversions permit predefined conversions that operate on non-nullable value types to also be used with nullable forms of those types. For each of the predefined implicit or explicit conversions that convert from a non-nullable value type S to a non-nullable value type T (§10.2.2, §10.2.3, §10.2.4, §10.2.11, §10.3.2 and §10.3.3), the following nullable conversions exist:

A nullable conversion is itself classified as an implicit or explicit conversion.

Certain nullable conversions are classified as standard conversions and can occur as part of a user-defined conversion. Specifically, all implicit nullable conversions are classified as standard implicit conversions (§10.4.2), and those explicit nullable conversions that satisfy the requirements of §10.4.3 are classified as standard explicit conversions.

Evaluation of a nullable conversion based on an underlying conversion from S to T proceeds as follows:

10.6.2 Lifted conversions

Given a user-defined conversion operator that converts from a non-nullable value type S to a non-nullable value type T, a lifted conversion operator exists that converts from S? to T?. This lifted conversion operator performs an unwrapping from S? to S followed by the user-defined conversion from S to T followed by a wrapping from T to T?, except that a null valued S? converts directly to a null valued T?. A lifted conversion operator has the same implicit or explicit classification as its underlying user-defined conversion operator.

10.7 Anonymous function conversions

10.7.1 General

An anonymous_method_expression or lambda_expression is classified as an anonymous function (§12.19). The expression does not have a type, but can be implicitly converted to a compatible delegate type. Some lambda expressions may also be implicitly converted to a compatible expression tree type.

Specifically, an anonymous function F is compatible with a delegate type D provided:

Example: The following examples illustrate these rules:

delegate void D(int x);
D d1 = delegate { };                         // Ok
D d2 = delegate() { };                       // Error, signature mismatch
D d3 = delegate(long x) { };                 // Error, signature mismatch
D d4 = delegate(int x) { };                  // Ok
D d5 = delegate(int x) { return; };          // Ok
D d6 = delegate(int x) { return x; };        // Error, return type mismatch

delegate void E(out int x);
E e1 = delegate { };                         // Error, E has an output parameter
E e2 = delegate(out int x) { x = 1; };       // Ok
E e3 = delegate(ref int x) { x = 1; };       // Error, signature mismatch

delegate int P(params int[] a);
P p1 = delegate { };                         // Error, end of block reachable
P p2 = delegate { return; };                 // Error, return type mismatch
P p3 = delegate { return 1; };               // Ok
P p4 = delegate { return "Hello"; };         // Error, return type mismatch
P p5 = delegate(int[] a)                     // Ok
{
   return a[0];
};
P p6 = delegate(params int[] a)              // Error, params modifier
{
   return a[0];
};
P p7 = delegate(int[] a)                     // Error, return type mismatch
{
   if (a.Length > 0) return a[0];
   return "Hello";
};

delegate object Q(params int[] a);
Q q1 = delegate(int[] a)                    // Ok
{
   if (a.Length > 0) return a[0];
   return "Hello";
};

end example

Example: The examples that follow use a generic delegate type Func<A,R> that represents a function that takes an argument of type A and returns a value of type R:

delegate R Func<A,R>(A arg);

In the assignments

Func<int,int> f1 = x => x + 1; // Ok
Func<int,double> f2 = x => x + 1; // Ok
Func<double,int> f3 = x => x + 1; // Error
Func<int, Task<int>> f4 = async x => x + 1; // Ok

the parameter and return types of each anonymous function are determined from the type of the variable to which the anonymous function is assigned.

The first assignment successfully converts the anonymous function to the delegate type Func<int,int> because, when x is given type int, x + 1 is a valid expression that is implicitly convertible to type int.

Likewise, the second assignment successfully converts the anonymous function to the delegate type Func<int,double> because the result of x + 1 (of type int) is implicitly convertible to type double.

However, the third assignment is a compile-time error because, when x is given type double, the result of x + 1 (of type double) is not implicitly convertible to type int.

The fourth assignment successfully converts the anonymous async function to the delegate type Func<int, Task<int>> because the result of x + 1 (of type int) is implicitly convertible to the effective return type int of the async lambda, which has a return type Task<int>.

end example

A lambda expression F is compatible with an expression tree type Expression<D> if F is compatible with the delegate type D. This does not apply to anonymous methods, only lambda expressions.

Anonymous functions may influence overload resolution, and participate in type inference. See §12.6 for further details.

10.7.2 Evaluation of anonymous function conversions to delegate types

Conversion of an anonymous function to a delegate type produces a delegate instance that references the anonymous function and the (possibly empty) set of captured outer variables that are active at the time of the evaluation. When the delegate is invoked, the body of the anonymous function is executed. The code in the body is executed using the set of captured outer variables referenced by the delegate. A delegate_creation_expression (§12.8.17.5) can be used as an alternate syntax for converting an anonymous method to a delegate type.

The invocation list of a delegate produced from an anonymous function contains a single entry. The exact target object and target method of the delegate are unspecified. In particular, it is unspecified whether the target object of the delegate is null, the this value of the enclosing function member, or some other object.

Conversions of semantically identical anonymous functions with the same (possibly empty) set of captured outer variable instances to the same delegate types are permitted (but not required) to return the same delegate instance. The term semantically identical is used here to mean that execution of the anonymous functions will, in all cases, produce the same effects given the same arguments. This rule permits code such as the following to be optimized.

delegate double Function(double x);

class Test
{
    static double[] Apply(double[] a, Function f)
    {
        double[] result = new double[a.Length];
        for (int i = 0; i < a.Length; i++)
        {
            result[i] = f(a[i]);
        }
        return result;
    }

    static void F(double[] a, double[] b)
    {
        a = Apply(a, (double x) => Math.Sin(x));
        b = Apply(b, (double y) => Math.Sin(y));
        ...
    }
}

Since the two anonymous function delegates have the same (empty) set of captured outer variables, and since the anonymous functions are semantically identical, a compiler is permitted to have the delegates refer to the same target method. Indeed, a compiler is permitted to return the very same delegate instance from both anonymous function expressions.

10.7.3 Evaluation of lambda expression conversions to expression tree types

Conversion of a lambda expression to an expression tree type produces an expression tree (§8.6). More precisely, evaluation of the lambda expression conversion produces an object structure that represents the structure of the lambda expression itself.

Not every lambda expression can be converted to expression tree types. The conversion to a compatible delegate type always exists, but it may fail at compile-time for implementation-defined reasons.

Note: Common reasons for a lambda expression to fail to convert to an expression tree type include:

end note

10.8 Method group conversions

An implicit conversion exists from a method group (§12.2) to a compatible delegate type (§20.4). If D is a delegate type, and E is an expression that is classified as a method group, then D is compatible with E if and only if E contains at least one method that is applicable in its normal form (§12.6.4.2) to any argument list (§12.6.2) having types and modifiers matching the parameter types and modifiers of D, as described in the following.

The compile-time application of the conversion from a method group E to a delegate type D is described in the following.

Example: The following demonstrates method group conversions:

delegate string D1(object o);
delegate object D2(string s);
delegate object D3();
delegate string D4(object o, params object[] a);
delegate string D5(int i);
class Test
{
   static string F(object o) {...}

   static void G()
   {
       D1 d1 = F;         // Ok
       D2 d2 = F;         // Ok
       D3 d3 = F;         // Error – not applicable
       D4 d4 = F;         // Error – not applicable in normal form
       D5 d5 = F;         // Error – applicable but not compatible
   }
}

The assignment to d1 implicitly converts the method group F to a value of type D1.

The assignment to d2 shows how it is possible to create a delegate to a method that has less derived (contravariant) parameter types and a more derived (covariant) return type.

The assignment to d3 shows how no conversion exists if the method is not applicable.

The assignment to d4 shows how the method must be applicable in its normal form.

The assignment to d5 shows how parameter and return types of the delegate and method are allowed to differ only for reference types.

end example

As with all other implicit and explicit conversions, the cast operator can be used to explicitly perform a particular conversion.

Example: Thus, the example

object obj = new EventHandler(myDialog.OkClick);

could instead be written

object obj = (EventHandler)myDialog.OkClick;

end example

A method group conversion can refer to a generic method, either by explicitly specifying type arguments within E, or via type inference (§12.6.3). If type inference is used, the parameter types of the delegate are used as argument types in the inference process. The return type of the delegate is not used for inference. Whether the type arguments are specified or inferred, they are part of the method group conversion process; these are the type arguments used to invoke the target method when the resulting delegate is invoked.

Example:

delegate int D(string s, int i);
delegate int E();

class X
{
   public static T F<T>(string s, T t) {...}
   public static T G<T>() {...}

   static void Main()
   {
       D d1 = F<int>;        // Ok, type argument given explicitly
       D d2 = F;             // Ok, int inferred as type argument
       E e1 = G<int>;        // Ok, type argument given explicitly
       E e2 = G;             // Error, cannot infer from return type
   }
}

end example

Method groups may influence overload resolution, and participate in type inference. See §12.6 for further details.

The run-time evaluation of a method group conversion proceeds as follows: