Compiler Error for Expression/Func overloads - c#

The screenshot says it pretty much.
I have the overloads as seen in the screenshot. When using a string as second parameter the compiler should figure out that the first argument can only be a Func and not an expression.
But the compiler throws an error saying 'A lamda expression with a statement body cannot be converted to an expression tree'.
Why can't the compiler figure out the correct overload?
Explicit cast does not help. What works is when i make a local variable of type Func and then use this instead.
The framework used is FakeItEasy 1.24.0
EDIT:
Here is the code that shows the behavior:
public static void Main(string[] args)
{
//compiler error
A.CallTo(() => Main(A<string[]>.That.Matches(strings =>
{
return true;
}, "description")));
//compiles
Func<string[], bool> predicate = strings =>
{
return true;
};
A.CallTo(() => Main(A<string[]>.That.Matches(predicate, "description")));
Console.ReadLine();
}

The issue is not in the call to Matches. It's in the call to CallTo, which expects an Expression<Action>.
Apparently an Expression not only can't be a lambda expression with a statement body, it also can't contain a lambda expression with a statement body.
(I'm not sure whether your "put the lambda in a local variable" solution will work or whether it just tricks the compiler and will fail at runtime.)
Here's the test I put together:
static void Overloaded(Action a, string param) { }
static void Overloaded(Expression<Action> e) { }
static void CallToAction(Action a) { }
static void CallToExprAc(Expression<Action> a) { }
static void Main(string[] args)
{
// Works
CallToAction(() => Overloaded(() => { int i = 5; }, "hi"));
// Doesn't work - using the Expression overload
CallToAction(() => Overloaded(() => { int i = 5; }));
// Doesn't work - wrapped in an outer Expression
CallToExprAc(() => Overloaded(() => { int i = 5; }, "hi"));
}
Whether your "put the expression-bodied lambda in a local" works is up to how FakeItEasy is implemented. I suspect it'll work here, but something similar in e.g. LINQ-to-SQL wouldn't - it'd just fail at runtime rather than at compile time.
I'm not sure whether this is a compiler bug, a spec bug or desirable behaviour. In section 6.5 of the C# spec we have
Certain lambda expressions cannot be converted to expression tree types: Even though the conversion exists, it fails at compile-time. This is the case if the lambda expression:
• Has a block body
• Contains simple or compound assignment operators
• Contains a dynamically bound expression
• Is async
which doesn't say "contains a lambda expression that cannot be converted to an expression tree type".

Related

Why does this Assert.Throws call resolve this way?

Using xUnit's Assert.Throws, I stumbled upon this (to me) hard to explain overload resolution issue. In xUnit, this method is marked obsolete:
[Obsolete("You must call Assert.ThrowsAsync<T> (and await the result) " +
"when testing async code.", true)]
public static T Throws<T>(Func<Task> testCode) where T : Exception
{ throw new NotImplementedException(); }
The question is, why does an inline statement lambda (or expression) that simply throws an exception resolve to this overload (and therefore doesn't compile)?
using System;
using Xunit;
class Program
{
static void Main(string[] args)
{
// this compiles (of course)
// resolves into the overload accepting an `Action`
Assert.Throws<Exception>(() => ThrowException());
// line below gives error CS0619 'Assert.Throws<T>(Func<Task>)' is obsolete:
// 'You must call Assert.ThrowsAsync<T> (and await the result) when testing async code.'
Assert.Throws<Exception>(() => { throw new Exception(); });
}
static void ThrowException()
{
throw new Exception("Some message");
}
}
I was able to reproduce this, given the function declarations:
static void CallFunction(Action action) { }
static void CallFunction(Func<Task> func) { }
And calling them:
CallFunction(() => ThrowException());
CallFunction(() => { throw new Exception(); });
The second one resolves into CallFunction(Func<Task> func) overload. The weird thing is if I change the body like this:
CallFunction(() => { int x = 1; });
It resolves to CallFunction(Action action) overload.
If the last statement in the body is a throw statement, I guess the compiler thinks method is returning something, and picks the closest -more specific- overload to that scenario which is Func<Task>.
The closest thing I found in the documentation is this:
7.5.2.12 Inferred return type
• If F is async and the body of F is either an expression classified as nothing (§7.1), or a statement block where no return statements have expressions, the inferred return type is System.Threading.Tasks.Task
The function here is a statement block, but it's not async though. Note that I'm not saying this exact rule applies here. Still I'm guessing it's related to this.
This article from Eric Lippert explains it better. (thanks for the comment #Damien_The_Unbeliever).
Here's a complete example which doesn't involve Task, to remove any hint of asynchrony being involved:
using System;
class Program
{
static void Method(Action action)
{
Console.WriteLine("Action");
}
static void Method(Func<int> func)
{
Console.WriteLine("Func<int>");
}
static void ThrowException()
{
throw new Exception();
}
static void Main()
{
// Resolvse to the Action overload
Method(() => ThrowException());
// Resolves to the Func<int> overload
Method(() => { throw new Exception(); });
}
}
Using section numbering from ECMA 334 (5th edition), we're interested in section 12.6.4 - overload resolution. The two important steps are:
Identify applicable methods (12.6.4.2)
Identify the best method (12.6.4.3)
We'll look at each call in turn
Call 1: () => ThrowException()
Let's start with the first call, which has an argument of () => ThrowException(). To check for applicability, we need a conversion from that argument to either Action or Func<int>. We can check that without involving overloading at all:
// Fine
Action action = () => ThrowException();
// Fails to compile:
// error CS0029: Cannot implicitly convert type 'void' to 'int'
// error CS1662: Cannot convert lambda expression to intended delegate type because
// some of the return types in the block are not implicitly convertible to the
// delegate return type
Func<int> func = () => ThrowException();
The CS1662 error is a little unfortunately worded in this case - it's not that there's a return type in the block that's not implicitly convertible to the delegate return type, it's that there isn't a return type in the lambda expression at all. The spec way of preventing this is in section 11.7.1. None of the permitted conversions there work. The closest is this (where F is the lambda expression and D is Func<int>):
If the body of F is an expression, and either F is non-async and D has a non-void return type T, or F is async and D has a return type Task<T>, then when each parameter of F is given the type of the corresponding parameter in D, the body of F is a valid expression (w.r.t §12) that is implicitly convertible to T.
In this case the expression ThrowException is not implicitly convertible to int, hence the error.
All of this means that only the first method is applicable for () => ThrowException(). Our pick for "best function member" is really easy when the set of applicable function members only has a single entry...
Call 2: () => { throw new Exception(); }
Now let's look at the second call, which has () => { throw new Exception(); } as the argument. Let's try the same conversions:
// Fine
Action action = () => { throw new Exception(); };
// Fine
Func<int> func = () => { throw new Exception(); };
Both conversions work here. The latter one works because of this bullet from 11.7.1:
If the body of F is a statement block, and either F is non-async and D has a
non-void return type T, or F is async and D has a return type Task<T>,
then when each parameter of F is given the type of the corresponding parameter in
D, the body of F is a valid statement block (w.r.t §13.3) with a nonreachable
end point in which each return statement specifies an expression that is implicitly
convertible to T.
I realize it sounds odd that this works, but:
The end point of the block is not reachable
There are no return statements, so the condition of "each return statement specifies [...]" is indeed met
To put it another way: you could use that block as the body of a method that's declared to return int.
That means both our methods are applicable in this case.
So which is better?
Now we need to look at section 12.6.4.3 to work out which method will actually be picked.
There are lots of rules here, but the one that decides things here is the conversion from the lambda expression to either Action or Func<int>. That's resolved in 12.6.4.4 (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 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:
D1 is a better conversion target than D2
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 (§12.6.3.13), and the conversion from X to Y1 is better than the conversion from X to Y2
E is async [... - skipped because it's not]
D1 has a return type Y, and D2 is void returning
The part I've put in bold is the important bit. When you consider the following scenario:
E is () => { throw new Exception(); }
T1 is Func<int> (so D1 is Func<int> too)
T2 is Action (so D2 is Action too)
... then both D1 and D2 have empty parameter lists, but D1 has a return type int, and D2 is void returning.
Therefore the conversion to Func<int> is better than the conversion to Action... which means that Method(Action) is a better function member than Member(Func<int>) for the second call.
Phew! Don't you just love overload resolution?

C# method overload resolution issues in Visual Studio 2013

Having these three methods available in Rx.NET library
public static IObservable<TResult> Create<TResult>(Func<IObserver<TResult>, CancellationToken, Task> subscribeAsync) {...}
public static IObservable<TResult> Create<TResult>(Func<IObserver<TResult>, CancellationToken, Task<IDisposable>> subscribeAsync) {...}
public static IObservable<TResult> Create<TResult>(Func<IObserver<TResult>, CancellationToken, Task<Action>> subscribeAsync) {...}
I write the following sample code in MSVS 2013:
var sequence =
Observable.Create<int>( async ( observer, token ) =>
{
while ( true )
{
token.ThrowIfCancellationRequested();
await Task.Delay( 100, token );
observer.OnNext( 0 );
}
} );
This does not compile due to ambiguous overloads. Exact output from the compiler being:
Error 1 The call is ambiguous between the following methods or properties:
'System.Reactive.Linq.Observable.Create<int>(System.Func<System.IObserver<int>,System.Threading.CancellationToken,System.Threading.Tasks.Task<System.Action>>)'
and
'System.Reactive.Linq.Observable.Create<int>(System.Func<System.IObserver<int>,System.Threading.CancellationToken,System.Threading.Tasks.Task>)'
However as soon as I replace while( true ) with while( false ) or with var condition = true; while( condition )...
var sequence =
Observable.Create<int>( async ( observer, token ) =>
{
while ( false ) // It's the only difference
{
token.ThrowIfCancellationRequested();
await Task.Delay( 100, token );
observer.OnNext( 0 );
}
} );
the error disappears and method call resolves to this:
public static IObservable<TResult> Create<TResult>(Func<IObserver<TResult>, CancellationToken, Task> subscribeAsync) {...}
What is going on there?
This is a fun one :) There are multiple aspects to it. To start with, let's simplify it very significantly by removing Rx and actual overload resolution from the picture. Overload resolution is handled at the very end of the answer.
Anonymous function to delegate conversions, and reachability
The difference here is whether the end-point of the lambda expression is reachable. If it is, then that lambda expression doesn't return anything, and the lambda expression can only be converted to a Func<Task>. If the end-point of the lambda expression isn't reachable, then it can be converted to any Func<Task<T>>.
The form of the while statement makes a difference because of this part of the C# specification. (This is from the ECMA C# 5 standard; other versions may have slightly different wording for the same concept.)
The end point of a while statement is reachable if at least one of the following is true:
The while statement contains a reachable break statement that exits the while statement.
The while statement is reachable and the Boolean expression does not have the constant value true.
When you have a while (true) loop with no break statements, neither bullet is true, so the end point of the while statement (and therefore the lambda expression in your case) is not reachable.
Here's a short but complete example without any Rx involved:
using System;
using System.Threading.Tasks;
public class Test
{
static void Main()
{
// Valid
Func<Task> t1 = async () => { while(true); };
// Valid: end of lambda is unreachable, so it's fine to say
// it'll return an int when it gets to that end point.
Func<Task<int>> t2 = async () => { while(true); };
// Valid
Func<Task> t3 = async () => { while(false); };
// Invalid
Func<Task<int>> t4 = async () => { while(false); };
}
}
We can simplify even further by removing async from the equation. If we have a synchronous parameterless lambda expression with no return statements, that's always convertible to Action, but it's also convertible to Func<T> for any T if the end of the lambda expression isn't reachable. Slight change to the above code:
using System;
public class Test
{
static void Main()
{
// Valid
Action t1 = () => { while(true); };
// Valid: end of lambda is unreachable, so it's fine to say
// it'll return an int when it gets to that end point.
Func<int> t2 = () => { while(true); };
// Valid
Action t3 = () => { while(false); };
// Invalid
Func<int> t4 = () => { while(false); };
}
}
We can look at this in a slightly different way by removing delegates and lambda expressions from the mix. Consider these methods:
void Method1()
{
while (true);
}
// Valid: end point is unreachable
int Method2()
{
while (true);
}
void Method3()
{
while (false);
}
// Invalid: end point is reachable
int Method4()
{
while (false);
}
Although the error method for Method4 is "not all code paths return a value" the way this is detected is "the end of the method is reachable". Now imagine those method bodies are lambda expressions trying to satisfy a delegate with the same signature as the method signature, and we're back to the second example...
Fun with overload resolution
As Panagiotis Kanavos noted, the original error around overload resolution isn't reproducible in Visual Studio 2017. So what's going on? Again, we don't actually need Rx involved to test this. But we can see some very odd behavior. Consider this:
using System;
using System.Threading.Tasks;
class Program
{
static void Foo(Func<Task> func) => Console.WriteLine("Foo1");
static void Foo(Func<Task<int>> func) => Console.WriteLine("Foo2");
static void Bar(Action action) => Console.WriteLine("Bar1");
static void Bar(Func<int> action) => Console.WriteLine("Bar2");
static void Main(string[] args)
{
Foo(async () => { while (true); });
Bar(() => { while (true) ; });
}
}
That issues a warning (no await operators) but it compiles with the C# 7 compiler. The output surprised me:
Foo1
Bar2
So the resolution for Foo is determining that the conversion to Func<Task> is better than the conversion to Func<Task<int>>, whereas the resolution for Bar is determining that the conversion to Func<int> is better than the conversion to Action. All the conversions are valid - if you comment out the Foo1 and Bar2 methods, it still compiles, but gives output of Foo2, Bar1.
With the C# 5 compiler, the Foo call is ambiguous by the Bar call resolves to Bar2, just like with the C# 7 compiler.
With a bit more research, the synchronous form is specified in 12.6.4.4 of the ECMA C# 5 specification:
C1 is a better conversion than C2 if at least one of the following holds:
...
E is an anonymous function, T1 is either a delegate type D1 or an expression tree type Expression, T2 is either a delegate type D2 or an expression tree type Expression and one of the following holds:
D1 is a better conversion target than D2 (irrelevant for us)
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 (§12.6.3.13), 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 (§12.6.3.13), 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
So that makes sense for the non-async case - and it also makes sense for how the C# 5 compiler isn't able to resolve the ambiguity, because those rules don't break the tie.
We don't have a full C# 6 or C# 7 specification yet, but there's a draft one available. Its overload resolution rules are expressed somewhat differently, and the change may be there somewhere.
If it's going to compile to anything though, I'd expect the Foo overload accepting a Func<Task<int>> to be chosen over the overload accepting Func<Task> - because it's a more specific type. (There's a reference conversion from Func<Task<int>> to Func<Task>, but not vice versa.)
Note that the inferred return type of the lambda expression would just be Func<Task> in both the C# 5 and draft C# 6 specifications.
Ultimately, overload resolution and type inference are really hard bits of the specification. This answer explains why the while(true) loop makes a difference (because without it, the overload accepting a func returning a Task<T> isn't even applicable) but I've reached the end of what I can work out about the choice the C# 7 compiler makes.
In addition to the answer from #Daisy Shipton I'd like to add that the same behavior can be observed in the following case, too:
var sequence = Observable.Create<int>(
async (observer, token) =>
{
throw new NotImplementedException();
});
basically because of the same reason - the compiler sees that the lambda function never returns so any return type would match, which in turn makes the lambda match any of the Observable.Create overloads.
And, finally, an example of simple solution: you can cast the lambda to the desired signature type to hint the compiler which Rx overload to choose.
var sequence =
Observable.Create<int>(
(Func<IObserver<int>, CancellationToken, Task>)(async (observer, token) =>
{
throw new NotImplementedException();
})
);

Is there a difference between C# lambda functions with brackets vs no brackets? [duplicate]

Fundamentally, is there any difference between a single-line expression lambda and a statement lambda? Take the following code, for example:
private delegate void MyDelegate();
protected static void Main()
{
MyDelegate myDelegate1 = () => Console.WriteLine("Test 1");
MyDelegate myDelegate2 = () => { Console.WriteLine("Test 2"); };
myDelegate1();
myDelegate2();
Console.ReadKey();
}
While I prefer the first because I find the brackets to be ugly, is there anything different between the two (besides the obvious part about requiring brackets for multi-line statements)?
You need statement lambda for multistatement lambdas. In addition statement lambdas are not supported by expression providers like LINQ to SQL. Before .NET 4.0 the .NET Framework did not have support for statement expression trees. This was added in 4.0 but as far as I know no provider uses it.
Action myDelegate1 = () => Console.WriteLine("Test 1");
Expression<Action> myExpression = () => { Console.WriteLine("Test 2") }; //compile error unless you remove the { }
myDelegate1();
Action myDelegate2 = myExpression.Compile();
myDelegate2();
Otherwise they are the same.
Reflector to the rescue! The disassembled code looks like this:
private static void Main(string[] args)
{
MyDelegate myDelegate1 = delegate {
Console.WriteLine("Test 1");
};
MyDelegate myDelegate2 = delegate {
Console.WriteLine("Test 2");
};
myDelegate1();
myDelegate2();
Console.ReadKey();
}
So no, there is no real difference between the two. Be happy.
The two are the same - the first is syntactic sugar to the second and both will compile to the same IL.
No, there is no difference in this example. If the body of the lambda is only one expression, you can drop the brackets. However, once the lambda contains more than one expression, like so:
MyDelegate myDelegate2 = () => {
Console.WriteLine("Test 2");
Console.WriteLine("Test 2");
};
the brackets are mandatory.
If the delegate returns a value, return is necessary in statement lambda as follows.
Func<int, int, bool> foo = (x, y) => { return x == y; };
Func<int, int, bool> goo = (x, y) => x == y;
Personnaly, i prefer the Lambda Expression. The Expression have a value where the Statement does not.
i think the following links can help you :
http://lambda-the-ultimate.org/node/1044
Same for the OP example, but after C# 6.0, allowing you to use same expression syntax to define normal non-lambda methods within a class. For example:
public static double AreaOfTriangle(double itsbase, double itsheight)
{
return itsbase * itsheight / 2;
}
The above code snippet can be written only if the method can be turned into a single expression. In short, it can be used the expression lambda syntax, but not the statement lambda syntax.
public static double
AreaOfTrianglex(double itsbase, double itsheight) => itsbase * itsheight / 2;
From the docs (https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions):
Statement lambdas, like anonymous methods, cannot be used to create expression trees.

Calling a void-parameter lambda gives compiler error

From this question: Lambda expression with a void input
I have the following very simple code:
int minutes = () => 9;
I get compiler error:
Cannot convert lambda expression to type 'int' because it is not a
delegate type
I've found several questions about this error but they're all about more specific issues. I actually want to give my lambda a body but thought I'd start simple first to check my syntax:
//I know this is a weird example
int minutes = ()=> { if(x==9) return 9; else return 5;}
From C# guide
A lambda expression is a block of code (an expression or a statement block) that is treated as an object. It can be passed as an argument to methods, and it can also be returned by method calls.
...
Lambda expressions are code that can be represented either as a delegate, or as an expression tree that compiles to a delegate.
That means lambda expression can be represented and can represent different things: delegate or expression tree.
Your expression
() => 9;
can be so many different things, as example
public class C {
delegate int IntDelegate();
public void M() {
Func<int> minutes = () => 9;
IntDelegate minutes2 = () => 9;
Expression<Func<int>> minutesExpression = () => 9;
Expression<IntDelegate> minutesExpression2 = () => 9;
}
}
So what do you want to use?
By the way, because of all that, you can't use var with them.
And you can see how c# compiler work under the hood for different lambda here-> lambda as delegate and expression tree

delegate keyword vs. lambda notation

Once it is compiled, is there a difference between:
delegate { x = 0; }
and
() => { x = 0 }
?
Short answer : no.
Longer answer that may not be relevant:
If you assign the lambda to a delegate type (such as Func or Action) you'll get an anonymous delegate.
If you assign the lambda to an Expression type, you'll get an expression tree instead of a anonymous delegate. The expression tree can then be compiled to an anonymous delegate.
Edit:
Here's some links for Expressions.
System.Linq.Expression.Expression(TDelegate) (start here).
Linq in-memory with delegates (such as System.Func) uses System.Linq.Enumerable. Linq to SQL (and anything else) with expressions uses System.Linq.Queryable. Check out the parameters on those methods.
An Explanation from ScottGu. In a nutshell, Linq in-memory will produce some anonymous methods to resolve your query. Linq to SQL will produce an expression tree that represents the query and then translate that tree into T-SQL. Linq to Entities will produce an expression tree that represents the query and then translate that tree into platform appropriate SQL.
I like Amy's answer, but I thought I'd be pedantic. The question says, "Once it is compiled" - which suggests that both expressions have been compiled. How could they both compile, but with one being converted to a delegate and one to an expression tree? It's a tricky one - you have to use another feature of anonymous methods; the only one which isn't shared by lambda expressions. If you specify an anonymous method without specifying a parameter list at all it is compatible with any delegate type returning void and without any out parameters. Armed with this knowledge, we should be able to construct two overloads to make the expressions completely unambiguous but very different.
But disaster strikes! At least with C# 3.0, you can't convert a lambda expression with a block body into an expression - nor can you convert a lambda expression with an assignment in the body (even if it is used as the return value). This may change with C# 4.0 and .NET 4.0, which allow more to be expressed in an expression tree. So in other words, with the examples MojoFilter happened to give, the two will almost always be converted to the same thing. (More details in a minute.)
We can use the delegate parameters trick if we change the bodies a little bit though:
using System;
using System.Linq.Expressions;
public class Test
{
static void Main()
{
int x = 0;
Foo( () => x );
Foo( delegate { return x; } );
}
static void Foo(Func<int, int> action)
{
Console.WriteLine("I suspect the anonymous method...");
}
static void Foo(Expression<Func<int>> func)
{
Console.WriteLine("I suspect the lambda expression...");
}
}
But wait! We can differentiate between the two even without using expression trees, if we're cunning enough. The example below uses the overload resolution rules (and the anonymous delegate matching trick)...
using System;
using System.Linq.Expressions;
public class Base
{
public void Foo(Action action)
{
Console.WriteLine("I suspect the lambda expression...");
}
}
public class Derived : Base
{
public void Foo(Action<int> action)
{
Console.WriteLine("I suspect the anonymous method...");
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
int x = 0;
d.Foo( () => { x = 0; } );
d.Foo( delegate { x = 0; } );
}
}
Ouch. Remember kids, every time you overload a method inherited from a base class, a little kitten starts crying.
In the two examples above there's no difference, zero.
The expression:
() => { x = 0 }
is a Lambda expression with statement body, so it can't be compiled as an expression tree. In fact it doesn't even compile because it needs a semicolon after 0:
() => { x = 0; } // Lambda statement body
() => x = 0 // Lambda expression body, could be an expression tree.
Amy B is correct. Note that there can be advantages to using expression trees. LINQ to SQL will examine the expression tree and convert it to SQL.
You can also play tricks with lamdas and expression trees to effectively pass the names of class members to a framework in a refactoring-safe way. Moq is an example of this.
There is a difference
Example:
var mytask = Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
return 2712;
});
mytask.ContinueWith(delegate
{
_backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});
And I replace with lambda:(error)
var mytask = Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
return 2712;
});
mytask.ContinueWith(()=>
{
_backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});
Some basics here.
This is a anonymous method
(string testString) => { Console.WriteLine(testString); };
As anonymous methods do not have names we need a delegate in which we can assign both of these methods or expressions. e.g.
delegate void PrintTestString(string testString); // declare a delegate
PrintTestString print = (string testString) => { Console.WriteLine(testString); };
print();
Same with the lambda expression. Usually we need a delegate to use them
s => s.Age > someValue && s.Age < someValue // will return true/false
We can use a func delegate to use this expression.
Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;
bool result = checkStudentAge ( Student Object);

Categories

Resources