I have a function with this signature:
public DeleteCommand(IService service,
Func<bool> canExecute, Action<ContactModel> deleted)
and code which calls it:
Delete = new DeleteCommand(
Service,
()=>CanDelete,
I don't understand what ()=>CanDelete exactly means. Being a Func<bool> it must return some value.
()=>
means it has no input parameters. But what is the value returned? why there is no return
in the lambda? Something like ()=> return CanDelete?
An expression lambda, which is what you have shown, returns the result of the expression following the =>. The return keyword is inferred, and in fact cannot be explicitly included. A statement lambda (which is of the form () => { someStatements;}) does not infer a return value, and requires an explicit return if it is not void.
Related
Simple syntactical question I can't seem to work out, I have a method which constructs a conditional event from a predicate and result, very simple call for code cleanliness and reusability.
public ValueUpdateEventHandler AddCondition(Func<float,bool> predicate, Action result)
{
ValueUpdateEventHandler func = (float value) => { if (predicate(value)) result(); };
onValueUpdate += func;
return func;
}
I would like to condense it to a single return statement, which accomplishes the construction and assignment all at once kind of like
return onValueUpdate += (float value) => { if (predicate(value)) result(); };
but this returns the entire onValueUpdate delegate. Is there away to return a reference to the anonymous member on the right of the function, which is added to the named member, instead of returning the named member, but accomplish it in a single clean line? This is more for readability, as this is a single usecase of a pattern I intend to implement repeatedly
Is this possible in C#? The following code produces a compiler error.
HashSet<Task<(string Value, int ToNodeId)>> regionTasks =
new HashSet<Task<(string Value, int ToNodeId)>>();
foreach (Connection connection in Connections[RegionName])
{
regionTasks.Add(async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
}());
}
The C# compiler complains, "Error CS0149: Method name expected." It's unable to infer the lambda method's return type.
Note my technique of invoking the lambda method immediately via the () after the the lambda block is closed {}. This ensures a Task is returned, not a Func.
The VB.NET compiler understands this syntax. I am stunned to find an example of the VB.NET compiler outsmarting the C# compiler. See my An Async Lambda Compiler Error Where VB Outsmarts C# blog post for the full story.
Dim regionTasks = New HashSet(Of Task(Of (Value As String, ToNodeId As Integer)))
For Each connection In Connections(RegionName)
regionTasks.Add(Async Function()
Dim value = Await connection.GetValueAsync(Key)
Return (value, connection.ToNode.Id)
End Function())
Next
The VB.NET compiler understands the End Function() technique. It correctly infers the lambda method's return type is Function() As Task(Of (Value As String, ToNodeId As Integer)) and therefore invoking it returns a Task(Of (Value As String, ToNodeId As Integer)). This is assignable to the regionTasks variable.
C# requires me to cast the lambda method's return value as a Func, which produces horribly illegible code.
regionTasks.Add(((Func<Task<(string Values, int ToNodeId)>>)(async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
}))());
Terrible. Too many parentheses! The best I can do in C# is explicitly declare a Func, then invoke it immediately.
Func<Task<(string Value, int ToNodeId)>> getValueAndToNodeIdAsync = async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
};
regionTasks.Add(getValueAndToNodeIdAsync());
Has anyone found a more elegant solution?
If .NET Standard 2.1 (or some .NET Framework versions, see compatibility list) is available for you, you can use LINQ with ToHashSet method:
var regionTasks = Connections[RegionName]
.Select(async connection =>
{
string value = await connection.GetValueAsync(Key);
return (Value: value, ToNodeId: connection.ToNode.Id);
})
.ToHashSet();
Or just initialize HashSet with corresponding IEnumerable.
UPD
Another workaround from linked in comments answer:
static Func<R> WorkItOut<R>(Func<R> f) { return f; }
foreach (Connection connection in Connections[RegionName])
{
regionTasks.Add(WorkItOut(async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
})());
}
When I first read the title of your question I thought "Eh? Who would propose trying to assign a value of type x to variable of type y, not in an inheritance relationship with x? That's like trying to assign an int to a string..."
I read the code, and that changed to "OK, this isn't assigning a delegate to a Task, this is just creating a Task and storing it in a collection of Tasks.. But it does look like they're assigning a delegate to a Task...
Then I saw
Note my technique of invoking the lambda method immediately via the () after the the lambda block is closed {}. This ensures a Task is returned, not a Func.
The fact that you have to explain this with commentary means it's a code smell and the wrong thing to do. Your code has gone from being readably self documenting, to a code golf exercise, using an arcane syntax trick of declaring a delegate and immediately executing it to create a Task. That's what we have Task.Run/TaskFactory.StartNew for, and it's what all the TAP code I've seen does when it wants a Task
You'll note that this form works and doesn't produce an error:
HashSet<Task<(string Value, int ToNodeId)>> regionTasks =
new HashSet<Task<(string Value, int ToNodeId)>>();
foreach (Connection connection in Connections[RegionName])
{
regionTasks.Add(Task.Run(async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
}));
}
It is far more clear how it works and the 7 characters you saved in not typing Task.Run means you don't have to write a 50+ character comment explaining why something that looks like a delegate can be assigned to a variable of type Task
I'd say the C# compiler was saving you from writing bad code here, and it's another case of the VB compiler letting developers play fast an loose and writing hard to understand code
An easy way to invoke asynchronous lambdas in order to get the materialized tasks, is to use a helper function like the Materialize below:
public static Task Materialize(Func<Task> taskFactory) => taskFactory();
public static Task<T> Materialize<T>(Func<Task<T>> taskFactory) => taskFactory();
Usage example:
regionTasks.Add(Materialize(async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
}));
I was reading about Web API 2 and Entity Framework where I bumped across this line:
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
I looked up the => operator and found that it has something to do with lambdas, although I'm still not sure exactly how it fits in or what's going on here. Can anybody help me out? What's going on in this line?
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
Basically means:
this.Database.Log = blah;
void blah(string s)
{
System.Diagnostics.Debug.WriteLine(s);
}
Database.Log is of the type Action<T>, which is a delegate type
See the property on MSDN
See Action<T> on MSDN
See delegates on MSDN
See lamdas on MSDN
So when this.Database wants to log stuff, it'll call it's "Log" property which is an Action<string>. Since it's an Action<string> (and more importantly, Action<T> is a delegate type), you can assign either a method which returns no value and has a single parameter (which is a string) or a lamda with a single parameter (also, string) (and no return value).
The Database.Log property is of type Action<string>. That means it's a delegate that takes a string and has no return value (i.e. its return type is void). So this line assigns the to the Log property an anonymous function which accepts a string value and writes it to the debugger window.
Because you're assigning the lambda expression to a property with a known delegate type, the compiler can infer the type of the argument (s) and return type from the context. This is shorthand for
this.Database.Log = (delegate (string s){ System.Diagnostics.Debug.WriteLine(s); });
Which in turn is short hand for (as the other answers mention) creating a private method and assigning a delegate reference to that private method:
this.Database.Log = (Action<string>)__compiler_generated_function__;
private void __compiler_generated_function__(string s) {
System.Diagnostics.Debug.WriteLine(s);
}
It means assign a function to this.Database.Log. When this.Database.Log executes it finds the function
s => System.Diagnostics.Debug.WriteLine(s);
That stands for
void LogMethod(string s)
{
System.Diagnostics.Debug.WriteLine(s);
}
I've got really simple code:
static void Main(string[] args)
{
var task = Task.Factory.StartNew(GetInt);
var task2 = Task.Factory.StartNew(
() =>
{
return GetInt();
});
}
static int GetInt()
{
return 64;
}
Why do I get a compiler error for the first task?
The method signatures (no params, return type is int) are equal, aren't they?
I know a solution(which is quite simple: var task = Task.Factory.StartNew<int>(GetInt);) but I'd like to know whats the problem with the code above.
You get an ambiguous call error because the method signature is the same.
Return values are not part of the signature.
Since you don't provide an explicit return type, the compiler doesn't know which to take.
Method Signature in C#
Because the compiler cannot decide which of these two overloads to use:
StartNew(Action)
StartNew<TResult>(Func<TResult>)
The reason for that is that the return type is not part of the overload resolution in C# (same way as you can't have two overloads only differing in return types) and therefore the compiler cannot decide whether GetInt should be an Action or a Func<T>. Forcing to use the generic version by calling StartNew<int>(GetInt) will provide the required information.
For the record, here are two more ways of doing it (that compile):
var task3 = Task.Factory.StartNew((Func<int>)GetInt);
var task4 = Task.Factory.StartNew(() => GetInt());
Would help to show the exception: "The call is ambiguous between the following methods or properties: 'System.Threading.Tasks.TaskFactory.StartNew(System.Action)' and 'System.Threading.Tasks.TaskFactory.StartNew(System.Func)'"
If you take a look there are two possible methods:
public Task<TResult> StartNew<TResult>(Func<TResult> function);
public Task StartNew(Action action);
If you add the <int> or supply a Func<int> you force it to take the first signature. Without that your code is ambiguous.
You get the compile error because the StartNew method takes in either an Action (returns void) or a Func (returns something) predicates with it's various overloads, and not a direct delegate.
As stated by others, you need to pass in GetInt as a function to StartNew, or specify that you intend to return a value from StartNew by supplying the generic type. Otherwise, the compiler has no idea what kind of task you intend to create....it is ambiguous.
static void Main(string[] args)
{
var task = Task.Factory.StartNew<int>(GetInt);
var task2 = Task.Factory.StartNew(
() =>
{
return GetInt();
});
}
static int GetInt()
{
return 64;
}
I'm reviewing another person's code and can't ask him... What does that line of C# code do?
It's a lambda expression that takes no parameter and returns true.
The equivalent anonymous delegate is:
delegate() { return true; };
Most likely the method requires a parameter of type Func<bool>, which is a generic delegate with the same signature as above code.
EDIT:
As noted by cdhowie, the above lambda can also be evaluated to an expression tree of type Expression<Func<bool>>.
Here's the equivalent expression tree:
var body = Expression.Constant(true);
Expression<Func<bool>> returnsTrueExpression = Expression.Lambda<Func<bool>>(body);
You can 'convert' it to an actual delegate by calling Compile()
Func<bool> returnsTrueFunc = returnsTrueExpression.Compile();
This is a lambda expression that always return true. This is a delegate that has functionality similar to this method
bool Test(){
return true;
}
The code reminds me of when you may want to stub or mock values in the early stages of creating unit tests.
You could have a class that has a method like:
bool result = SomeClass.RunSomeImportantProcess(Func<bool> process)
and in your tests you might want to do something as a stub like
Assert.IsTrue(SomeClass.RunSomeImportantProcess(() => true));
Its a lambda expression which doesn't take any parameter but returns true. Whether its required or not, you would have to provide more info to determine.