ЗНАЕТЕ ЛИ ВЫ?

Better conversion from expression



Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, C1 is a better conversion than C2 if at least one of the following holds:

· E has a type S and an identity conversion exists from S to T1 but not from S to T2

· E is not an anonymous function and T1 is a better conversion target than T2 (§7.5.3.5)

· E is an anonymous function, T1 is either a delegate type D1 or an expression tree type Expression<D1>, T2 is either a delegate type D2 or an expression tree type Expression<D2> and one of the following holds:

o D1 is a better conversion target than D2

o D1 and D2 have identical parameter lists, and one of the following holds:

· D1 has a return type Y1, and D2 has a return type Y2, an inferred return type X exists for E in the context of that parameter list (§7.5.2.12), and the conversion from X to Y1 is better than the conversion from X to Y2

· E is async, D1 has a return type Task<Y1>, and D2 has a return type Task<Y2>, an inferred return type Task<X> exists for E in the context of that parameter list (§7.5.2.12), and the conversion from X to Y1 is better than the conversion from X to Y2

· D1 has a return type Y, and D2 is void returning

Better conversion from type

Given a conversion C1 that converts from a type S to a type T1, and a conversion C2 that converts from a type S to a type T2, C1 is a better conversion than C2 if at least one of the following holds:

· An identity conversion exists from S to T1 but not from S to T2

· T1 is a better conversion target than T2 (§7.5.3.5)

Better conversion target

Given two different types T1 and T2, T1 is a better conversion target than T2 if at least one of the following holds:

· An implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists

· T1 is a signed integral type and T2 is an unsigned integral type. Specifically:

o T1 is sbyte and T2 is byte, ushort, uint, or ulong

o T1 is short and T2 is ushort, uint, or ulong

o T1 is int and T2 is uint, or ulong

o T1 is long and T2 is ulong

Overloading in generic classes

While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.

The following examples show overloads that are valid and invalid according to this rule:

interface I1<T> {...}

interface I2<T> {...}

class G1<U>
{
int F1(U u); // Overload resulotion for G<int>.F1
int F1(int i); // will pick non-generic

void F2(I1<U> a); // Valid overload
void F2(I2<U> a);
}

class G2<U,V>
{
void F3(U u, V v); // Valid, but overload resolution for
void F3(V v, U u); // G2<int,int>.F3 will fail

void F4(U u, I1<V> v); // Valid, but overload resolution for
void F4(I1<V> v, U u); // G2<I1<int>,int>.F4 will fail

void F5(U u1, I1<V> v2); // Valid overload
void F5(V v1, U u2);

void F6(ref U u); // valid overload
void F6(out V v);
}

Compile-time checking of dynamic overload resolution

For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. In certain cases, however the candidate set is known at compile-time:

· Static method calls with dynamic arguments

· Instance method calls where the receiver is not a dynamic expression

· Indexer calls where the receiver is not a dynamic expression

· Constructor calls with dynamic arguments

In these cases a limited compile-time check is performed for each candidate to see if any of them could possibly apply at run-time.This check consists of the following steps:

· Partial type inference: Any type argument that does not depend directly or indirectly on an argument of type dynamic is inferred using the rules of §7.5.2. The remaining type arguments are unknown.

· Partial applicability check: Applicability is checked according to §7.5.3.1, but ignoring parameters whose types are unknown.

If no candidate passes this test, a compile-time error occurs.

Function member invocation

This section describes the process that takes place at run-time to invoke a particular function member. It is assumed that a binding-time process has already determined the particular member to invoke, possibly by applying overload resolution to a set of candidate function members.

For purposes of describing the invocation process, function members are divided into two categories:

· Static function members. These are instance constructors, static methods, static property accessors, and user-defined operators. Static function members are always non-virtual.

· Instance function members. These are instance methods, instance property accessors, and indexer accessors. Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. The instance is computed by an instance expression, and it becomes accessible within the function member as this (§7.6.7).

The run-time processing of a function member invocation consists of the following steps, where M is the function member and, if M is an instance member, E is the instance expression:

· If M is a static function member:

o The argument list is evaluated as described in §7.5.1.

o M is invoked.

· If M is an instance function member declared in a value-type:

o E is evaluated. If this evaluation causes an exception, then no further steps are executed.

o If E is not classified as a variable, then a temporary local variable of E’s type is created and the value of E is assigned to that variable. E is then reclassified as a reference to that temporary local variable. The temporary variable is accessible as this within M, but not in any other way. Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.

o The argument list is evaluated as described in §7.5.1.

o M is invoked. The variable referenced by E becomes the variable referenced by this.

· If M is an instance function member declared in a reference-type:

o E is evaluated. If this evaluation causes an exception, then no further steps are executed.

o The argument list is evaluated as described in §7.5.1.

o If the type of E is a value-type, a boxing conversion (§4.3.1) is performed to convert E to type object, and E is considered to be of type object in the following steps. In this case, M could only be a member of System.Object.

o The value of E is checked to be valid. If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.

o The function member implementation to invoke is determined:

· If the binding-time type of E is an interface, the function member to invoke is the implementation of M provided by the run-time type of the instance referenced by E. This function member is determined by applying the interface mapping rules (§13.4.4) to determine the implementation of M provided by the run-time type of the instance referenced by E.

· Otherwise, if M is a virtual function member, the function member to invoke is the implementation of M provided by the run-time type of the instance referenced by E. This function member is determined by applying the rules for determining the most derived implementation (§10.6.3) of M with respect to the run-time type of the instance referenced by E.

· Otherwise, M is a non-virtual function member, and the function member to invoke is M itself.

o The function member implementation determined in the step above is invoked. The object referenced by E becomes the object referenced by this.





Последнее изменение этой страницы: 2016-12-14; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 34.201.3.10 (0.008 с.)