A delegate-creation-expression is used to create a new instance of a delegate-type.
The argument of a delegate creation expression must be a method group or a value of a delegate-type. If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. If the argument is a value of a delegate-type, it identifies a delegate instance of which to create a copy.
The compile-time processing of a delegate-creation-expression of the form new
D(E)
, where D
is a delegate-type and E
is an expression, consists of the following steps:
E
is a method group:
E
must include exactly one method with precisely the same signature and return type as those of D
, and this becomes the method to which the newly created delegate refers. If no matching method exists, or if more than one matching methods exists, an error occurs. If the selected method is an instance method, the instance expression associated with E
determines the target object of the delegate.D
, namely a newly created delegate that refers to the selected method and target object.E
is a value of a delegate-type:
E
must have the exact same signature and return type as D
, or otherwise an error occurs.D
, namely a newly created delegate that refers to the same method and target object as E
.The run-time processing of a delegate-creation-expression of the form new
D(E)
, where D
is a delegate-type and E
is an expression, consists of the following steps:
E
is a method group:
null
. Otherwise, the selected method is an instance method, and the target object of the delegate is determined from the instance expression associated with E
:
null
, a NullReferenceException
is thrown and no further steps are executed.D
is allocated. If there is not enough memory available to allocate the new instance, an OutOfMemoryException
is thrown and no further steps are executed.E
is a value of a delegate-type:
E
is evaluated. If this evaluation causes an exception, no further steps are executed.E
is null
, a NullReferenceException
is thrown and no further steps are executed.D
is allocated. If there is not enough memory available to allocate the new instance, an OutOfMemoryException
is thrown and no further steps are executed.E
.The method and object to which a delegate refers are determined when the delegate is instantiated and then remain constant for the entire lifetime of the delegate. In other words, it is not possible to change the target method or object of a delegate once it has been created.
It is not possible to create a delegate that refers to a constructor, property, indexer, or user-defined operator.
As described above, when a delegate is created from a method group, the signature and return type of the delegate determine which of the overloaded methods to select. In the example
delegate double DoubleFunc(double x); class A { DoubleFunc f = new DoubleFunc(Square); static float Square(float x) { return x * x; } static double Square(double x) { return x * x; } }
the A.f
field is initialized with a delegate that refers to the second Square
method because that method exactly matches the signature and return type of DoubleFunc
. Had the second Square
method not been present, a compile-time error would have occurred.