The parameters are defined, it's just that their types are inferred. The argument definition is the part before the =>
- list
(inferred to be of type IList<T>
) and x
(inferred to be of type float
) respectivelly in your examples.
The first delegate corresponds to a signature of:
T SomeMethod<T>(IList<T> list)
The second is:
float SomeMethod(float x)
Since the compiler knows what the signature of the delegate must be, it can infer the required types automatically. If you were to write out the delegate using the old-school explicit syntax, it would look something like this:
return (Func<IList<T>, T>)(delegate (IList<T> list) { return list.First(); });
If you really want to use explicit typing, you can specify the types as needed:
(IList<T> list) => list.First()
When you actually want to invoke the delegate, you need to pass the argument, e.g.:
SelectionMethod<string>()(new List<string>())
The first lambda expression is very simple. The second additionally closes over the arguments to the "creator" function, which means that you can access the arguments to the "creator" in the body of the delegate. This is entirely safe in purely immutable code, but may be tricky if you're dealing with mutable reference types and side-effects - make sure you understand the semantics properly before you do anything crazy with those.
Depending on your experience with functional programming, it might be helpful to realize that all of this is just compiler trickery. The two methods will compile to the equivalent of something like this:
public Func<IList<T>, T> SelectionMethod<T>()
{
return new Func<IList<T>, T>(__HiddenAnonymousMethod);
}
private T __HiddenAnonymousMethod<T>(IList<T> list)
{
return list.First();
}
The second example is more complicated because of the closure - we need to create a "helper object" to hold the captured locals:
private class __HiddenAnonymousClass
{
float a, b, c;
public __HiddenAnonymousClass(float a, float b, float c)
{
this.a = a; this.b = b; this.c = c;
}
public float __HiddenAnonymousMethod(float x)
{
return a * x * x + b * x + c;
}
}
public Func<float, float> QuadraticFunctionMaker(float a , float b , float c)
{
return new Func<float, float>
(new __HiddenAnonymousClass(a, b, c).__HiddenAnonymousMethod);
}