Get result from Delegate Invocation list - c#

I have very simple question. I have very little understanding of Delegates and Lambda Expressions in C#. I have code:
class Program
{
delegate int del(int i);
static void Main(string[] args)
{
del myDelegate = Multiply;
int j;
myDelegate = x => { Console.WriteLine("Lambda Expression Called..."); return x * x; };
myDelegate += Multiply;
myDelegate += Increment;
j = myDelegate(6);
Console.WriteLine(j);
Console.ReadKey();
}
public static int Multiply(int num)
{
Console.WriteLine("Multiply Called...");
return num * num;
}
public static int Increment(int num)
{
Console.WriteLine("Increment Called...");
return num += 1;
}
}
And the result is:
Lambda Expression Called...
Multiply Called...
Increment Called...
7
It shows the result 7 of the last method called from invocation list.
How can I get the result of each method from Delegate Invocation List? I have seen this thread but I couldn't grasp the idea. I will appreciate if you can provide answer with my code provided above.
Thank You!

It's fairly unusual to use the multicast capability of .NET delegates for anything other than event-subscribers (consider simply using a collection instead).
That said, it's possible to get the individual delegates comprising a multicast delegate (with Delegate.GetInvocationList) and invoke each of them in turn instead of getting the framework to do it for you (by invoking the multicast delegate directly). This way, it's possible to inspect the return-value of each member of the invocation list.
foreach(del unicastDelegate in myDelegate.GetInvocationList())
{
int j = unicastDelegate(6);
Console.WriteLine(j);
}
Output:
Lambda Expression Called...
36
Multiply Called...
36
Increment Called...
7

Related

Call a method with an unknown signature

I'm using C# 4.6.2, though could upgrade to 4.7.2 if it's possible there.
In many places in our code we have a loop with wait statements to check for a specific value when a function is called, wait and retry if it's not what we wanted until a maximum number of retries.
I'd like to abstract this out, but the only implementation I can think of requires you pass in a method with a variable number of arguments of variable types, which after much searching of Google appeared to not be possible about 5 years ago. There has been many improvements to C# since then, so
is it still not possible?
If it is now possible how do I do it?
If it isn't possible can you think of any other way I can achieve my goal?
The sort of thing I'm looking for is:
public bool GenericLoopWait(int maxWaitSeconds, int waitMsPerIteration,??? DoSomething,object expectedResult,...)
int maxRetries = maxWaitSeconds*1000/waitMsPerIteration;
SomeType result=null;
for(int i=0; i<maxRetries; i++){
result = DoSomething(...);
if(result==expectedResult) break;
Thread.Sleep(waitMsPerIteration);
}
return result==expectedResult
}
And then both of these would work:
GenericLoopWait(5,500,Browser.Webdriver.FindElements(selector).Any(),true);
GenericLoopWait(5,500,Api.GetSpecificObject(api,objectName),"expectedOutcome");
You could use generics and Func and wrap the actual calls parameters when you call through to the method.
public bool GenericLoopWait<T>(int maxWaitSeconds, int waitMsPerIteration, Func<T> DoSomething, T expectedResult = default(T))
{
int maxRetries = maxWaitSeconds * 1000 / waitMsPerIteration;
T result = default(T);
for (int i = 0; i < maxRetries; i++)
{
result = DoSomething();
if (expectedResult.Equals(result)) break;
Thread.Sleep(waitMsPerIteration);
}
return expectedResult.Equals(result);
}
Calling code:
GenericLoopWait(5, 500, () => Browser.Webdriver.FindElements(selector).Any(), true);
GenericLoopWait(5, 500, () => Api.GetSpecificObject(api,objectName), "expectedOutcome")
Working dotnetfiddle
The general pattern is to create a "Wrapper" method that accepts an Action or a Func as a parameter. Your wrapper can do it's own logic, and Invoke the parameter at the correct time.
As a simple generic example:
public void MethodWrapper(Action action)
{
Console.WriteLine("begin");
action.Invoke();
Console.WriteLine("end");
}
You could then do this:
void Main()
{
var a = 1;
var b = 2;
MethodWrapper(() => DoSomething(a));
MethodWrapper(() => DoSomethingElse(a,b));
}
public void DoSomething(int a)
{
Debug.WriteLine($"a={a}");
}
public void DoSomethingElse(int a, int b)
{
Debug.WriteLine($"a={a}, b={b}");
}
To generate this output:
begin
a=1
end
begin
a=1, b=2
end
For your specific case, your wrapper could take additional parameters specifying things like number of retries, time between calls, or acceptance criteria.

Delegate instances vs passing function directly

I am curious as to what is the point of creating instances of delegates. I understand that they are function pointers but what is the purpose of the using delegate instances?
public delegate bool IsEven(int x);
class Program
{
static void Main(string[] args)
{
int[] nums = new int[] { 1, 3, 4, 5, 6,7, 8, 9 };
// creating an instance of delegate and making it point to 'CheckEven' function
IsEven isEven = new IsEven(CheckEven);
// using delegate for parameter to get sum of evens
int tot1 = Sums(nums, isEven);
// passing in the function directly as parameter and not delegate instance
int tot2 = Sums(nums, CheckEven);
// using lambda expressions
int tot3 = Sums(nums, x=> x%2==0);
ReadKey();
}
public static int Sums(int[] nums, IsEven isEvenOdd)
{
int sum = 0;
foreach(int x in nums)
{
if (isEvenOdd(x))
sum += x;
}
return sum;
}
public static bool CheckEven(int x)
{
if (x % 2 == 0)
return true;
else
return false;
}
}
At first thought opting to always use lambdas seems like the best idea if the functionality of the function you are going to pass does not have complex implementation, otherwise why wouldn't I just pass my function directly into the parameters? Also with Lambdas it is much easier to change it to compute the sum of odds as oppose to creating an entire new method as I would have to with delegates.
You already used delegates even if you passed the method directly, the Sums method could not receive the method name if it's not set its expectation by the delegate definition.
Consider changing the delegate name to public delegate bool EvenOddStatus(int x);
you can send either your CheckEven method or this method:
public static bool CheckOdd(int x)
{
if (x % 2 != 0) // here changed
return true;
else return false;
}
(of course you can use lambda here, but not in more complicated scenarios)
Now your Sums method can sum up either odd or even numbers based on the calling code (either pass CheckEven or CheckOdd).
Delegates are pointers to methods. you define how the code want the method to receive and return, and the calling code can pass a pre-defined implementation later, either a method or delegate.
What if your Main is another method that doesn't know what to sum, odds or evens? it will have a delegate from a calling code up the stack.

C#: delegates, compact visitor, "universal callable" argument type

I'm looking for a compact way to implement visitor in C#.
The code is going to be used in Unity3D in "object hierarchy walker" function.
The main problem is that I don't know how to declare "universal callable argument" as a method parameter in C#.
static void visitorTest(var visitor){ // <<---- which type?
int i = 0;
visitor(i);
}
which can be easily expressed in C++ template functions
template<class Visitor> void visitorTest(Visitor visitor){
visitor(i);
}
Ideally vistior should accept class, method (or static method) and some sort of "lambda" expression. Accepting "class" is optional.
I did try to write it in C# using information from here and here, but I did not get it right.
I'm missing some fundamental knowledge mostly related to conversion between delegates, Action, methods and Func, would be nice if someone pointed what exactly I don't know yet or just threw example at me so I can figure it out myself (fixing two compile errors would be less time consuming than explaining everything).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleTest
{
class Program
{
public delegate void Visitor(int i);
public void visitorTest(Visitor visitor){
int[] tmp = new int[10];
for (int i = 0; i < tmp.Length; i++){
tmp[i] = i;
}
foreach(var i in tmp){
visitor(i);
}
}
public static void funcCallback(int arg) {
System.Console.WriteLine("func: " + arg.ToString());
}
static void Main(string[] args)
{
//An object reference is required for the non-static field, method, or property 'ConsoleTest.Program.visitorTest(ConsoleTest.Program.Visitor)
visitorTest(new Visitor(funcCallback));
int mul = 2;
Action< int> lambda = (i) => System.Console.WriteLine("lambda: " + (2*i).ToString());
//The best overloaded method match for 'ConsoleTest.Program.visitorTest(ConsoleTest.Program.Visitor)' has some invalid arguments
//Argument 1: cannot convert from 'System.Action<int>' to 'ConsoleTest.Program.Visitor'
visitorTest(lambda);
}
}
}
C++ code example:
Ideally I would like to have equivalent of this code fragment (C++):
#include <vector>
#include <iostream>
template<class Visitor> void visitorTest(Visitor visitor){
//initialization, irrelevant:
std::vector<int> tmp(10);
int i = 0;
for(auto& val: tmp){
val =i;
i++;
}
//processing:
for(auto& val: tmp)
visitor(val);
}
//function visitor
void funcVisitor(int val){
std::cout << "func: " << val << std::endl;
}
//class visitor
class ClassVisitor{
public:
void operator()(int arg){
std::cout << "class: " << arg*val << std::endl;
}
ClassVisitor(int v)
:val{v}{
}
protected:
int val;
};
int main(){
visitorTest(funcVisitor);
visitorTest(ClassVisitor(2));
int arg = 3;
/*
* lambda visitor: equivalent to
*
* void fun(int x){
* }
*/
visitorTest([=](int x){ std::cout << "lambda: " << arg*x << std::endl;});
}
Output:
func: 0
func: 1
func: 2
func: 3
func: 4
func: 5
func: 6
func: 7
func: 8
func: 9
class: 0
class: 2
class: 4
class: 6
class: 8
class: 10
class: 12
class: 14
class: 16
class: 18
lambda: 0
lambda: 3
lambda: 6
lambda: 9
lambda: 12
lambda: 15
lambda: 18
lambda: 21
lambda: 24
lambda: 27
visitorTest is a universal (template) function that can take lambda expression, class or a function as a callback.
funcTest is function callback.
classTest is a class callback.
and the last line within main() has lambda callback.
I can make class based callback easily by providing abstract base of sorts, but I'd like to have more flexible approach, because writing full blown class is often too verbose, and writing abstract base for something this simple is overkill.
Online information suggests that the way to do it is to use Linq and Delegates, but I have trouble converting between them or just passing along the delegate.
Advice?
Remove your Visitor delegate, and just specify the input parameter as Action, which can be any method that takes one int parameter.
using System;
namespace Testing
{
internal class Program
{
public static void visitorTest(Action<int> visitor)
{
int[] tmp = new int[10];
for (int i = 0; i < tmp.Length; i++)
{
tmp[i] = i;
}
foreach (var i in tmp)
{
visitor(i);
}
}
public static void funcCallback(int arg)
{
System.Console.WriteLine("func: " + arg.ToString());
}
private static void Main(string[] args)
{
//An object reference is required for the non-static field, method, or property 'ConsoleTest.Program.visitorTest(ConsoleTest.Program.Visitor)
visitorTest(funcCallback);
int mul = 2;
Action<int> lambda = (i) => System.Console.WriteLine("lambda: " + (2 * i).ToString());
//The best overloaded method match for 'ConsoleTest.Program.visitorTest(ConsoleTest.Program.Visitor)' has some invalid arguments
//Argument 1: cannot convert from 'System.Action<int>' to 'ConsoleTest.Program.Visitor'
visitorTest(lambda);
Console.Read();
}
}
}
Output looks like:
func: 0
func: 1
func: 2
func: 3
func: 4
func: 5
func: 6
func: 7
func: 8
func: 9
lambda: 0
lambda: 2
lambda: 4
lambda: 6
lambda: 8
lambda: 10
lambda: 12
lambda: 14
lambda: 16
lambda: 18
After a bit of messing around, I figured out how to use delegates properly. Updated example is below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleTest
{
class Program
{
public delegate void Visitor(int i);
public static void visitorTest(Visitor visitor){
int[] tmp = new int[10];
for (int i = 0; i < tmp.Length; i++){
tmp[i] = i;
}
foreach(var i in tmp){
visitor(i);
}
}
public static void funcCallback(int arg) {
System.Console.WriteLine("func: " + arg.ToString());
}
static void Main(string[] args)
{
visitorTest(funcCallback);
int mul = 2;
visitorTest((int i)=>{System.Console.WriteLine("lambda: " + (mul*i).ToString());});
Action<int> lambda = (int i) => { System.Console.WriteLine("lambda: " + (3 * i).ToString()); };
visitorTest(lambda.Invoke);
}
}
}
I also gave up on on passing class instances as callbacks, because I can do that through lambdas anyway.
Explanation (in case someone stumbles into this later):
public delegate void Visitor(int i);
this line declares "delegate" type named Visitor, which is essentially somewhat equivalent to C++ function pointer.After declaration it can be used as parameter:
public static void visitorTest(Visitor visitor){
And called using normal function call syntax.
visitor(i);
Methods and lambda expressions can be assigned to this type normally.
visitorTest(funcCallback);
visitorTest((int i)=>{System.Console.WriteLine("lambda: " + (mul*i).ToString());});
Also, this SO thread discussess differences between Action<>/Func<> and delegates.

Executing multicast delegates

I have a Multiple target
Func<int,int,int> funHandler=Max;
funHandler+=square;
When i execute
Console.WriteLine(funHandler(10,10)); it return the square of 10 (i.e) 200.It did not fire Max.
i used something like
foreach(var v in funHandler.GetInvocationList())
{
Console.WriteLine(v(10,20));
}
'V' is a variable,but it is used like a method.How can i fire all methods that is in delegate's
invocation list?
Well, may be Max has no side effects and you can't notice it? When you execute multicast delegate it returns result of only last delegate.
Try this:
Func<int, int, int> funHandler = (x, y) => { Console.WriteLine(x); return x; };
funHandler += (x, y) => { Console.WriteLine(y); return y; };
int res = funHandler(1, 2);
Console.WriteLine(res);
See? it works
To use invocation list do this:
foreach (var v in funHandler.GetInvocationList())
{
((Func<int, int, int>)v)(1, 2);
}
Or:
foreach (Func<int, int, int> v in funHandler.GetInvocationList())
{
v(1, 2);
}
Multicast with a delegate that returns something doesn't make much sense to me. I'd guess it executes all of them but discards all results but one.

Cannot use ref or out parameter in lambda expressions

Why can't you use a ref or out parameter in a lambda expression?
I came across the error today and found a workaround but I was still curious why this is a compile-time error.
CS1628: Cannot use in ref or out parameter 'parameter' inside an anonymous method, lambda expression, or query expression
Here's a simple example:
private void Foo()
{
int value;
Bar(out value);
}
private void Bar(out int value)
{
value = 3;
int[] array = { 1, 2, 3, 4, 5 };
int newValue = array.Where(a => a == value).First();
}
Lambdas have the appearance of changing the lifetime of variables that they capture. For instance, the following lambda expression causes the parameter p1 to live longer than the current method frame as its value can be accessed after the method frame is no longer on the stack
Func<int> Example(int p1) {
return () => p1;
}
Another property of captured variables is that changes to the variables are also visible outside the lambda expression. For example, the following code prints out 42
void Example2(int p1) {
Action del = () => { p1 = 42; };
del();
Console.WriteLine(p1);
}
These two properties produce a certain set of effects which fly in the face of a ref parameter in the following ways:
ref parameters may have a fixed lifetime. Consider passing a local variable as a ref parameter to a function.
Side effects in the lambda would need to be visible on the ref parameter itself. Both within the method and in the caller.
These are somewhat incompatible properties and are one of the reasons they are disallowed in lambda expressions.
Under the hood, the anonymous method is implemented by hoisting captured variables (which is what your question body is all about) and storing them as fields of a compiler generated class. There is no way to store a ref or out parameter as a field. Eric Lippert discussed it in a blog entry. Note that there is a difference between captured variables and lambda parameters. You can have "formal parameters" like the following as they are not captured variables:
delegate void TestDelegate (out int x);
static void Main(string[] args)
{
TestDelegate testDel = (out int x) => { x = 10; };
int p;
testDel(out p);
Console.WriteLine(p);
}
You can but you must explicitly define all the types so
(a, b, c, ref d) => {...}
Is invalid, however
(int a, int b, int c, ref int d) => {...}
Is valid
As this is one of the top results for "C# lambda ref" on Google; I feel I need to expand on the above answers. The older (C# 2.0) anonymous delegate syntax works and it does support more complex signatures (as well closures). Lambda's and anonymous delegates at the very least have shared perceived implementation in the compiler backend (if they are not identical) - and most importantly, they support closures.
What I was trying to do when I did the search, to demonstrate the syntax:
public static ScanOperation<TToken> CreateScanOperation(
PrattTokenDefinition<TNode, TToken, TParser, TSelf> tokenDefinition)
{
var oldScanOperation = tokenDefinition.ScanOperation; // Closures still work.
return delegate(string text, ref int position, ref PositionInformation currentPosition)
{
var token = oldScanOperation(text, ref position, ref currentPosition);
if (token == null)
return null;
if (tokenDefinition.LeftDenotation != null)
token._led = tokenDefinition.LeftDenotation(token);
if (tokenDefinition.NullDenotation != null)
token._nud = tokenDefinition.NullDenotation(token);
token.Identifier = tokenDefinition.Identifier;
token.LeftBindingPower = tokenDefinition.LeftBindingPower;
token.OnInitialize();
return token;
};
}
Just keep in mind that Lambdas are procedurally and mathematically safer (because of the ref value promotion mentioned earlier): you might open a can of worms. Think carefully when using this syntax.
And maybe this?
private void Foo()
{
int value;
Bar(out value);
}
private void Bar(out int value)
{
value = 3;
int[] array = { 1, 2, 3, 4, 5 };
var val = value;
int newValue = array.Where(a => a == val).First();
}
You can not use an out parameter directly in a lambda expression. The reason why you can not do that is explained in the other answers.
Workaround
But you can use a local temporary variable with for the inner function and, after the inner function has been executed, assign the out value from the inner function to the out value of the outer function:
private static int OuterFunc (int i_param1, out int o_param2)
{
int param2 = 0;
var del = () => InnerFunc (i_param1, out param2);
int result = del ();
o_param2 = param2;
return result;
}
private static int InnerFunc (int i_param1, out int o_param2)
{
o_param2 = i_param1;
return i_param1;
}
private static void Main (string[] args)
{
int result = OuterFunc (123, out int param2);
Console.WriteLine (result); // prints '123'
Console.WriteLine (param2); // prints '123'
}
Please note
The question was created in 2009. My answer was created in 2023 using C#10 and .NET 6. I don't know whether this answer had also worked back in 2009, which means, the code here might depend on enhancements to C# and .NET that might have been made in the meantime.
I will give you another example.
Description
The code below will throw out this error. Because the change brought by the lambda expression (i)=>{...} only works in the function test.
static void test(out System.Drawing.Image[] bitmaps)
{
int count = 10;
bitmaps = new System.Drawing.Image[count];
Parallel.For(0, count, (i) =>
{
bitmaps[i] = System.Drawing.Image.FromFile("2.bmp");
});
}
Solution
So, if you remove out of the parameter, it works.
static void test(System.Drawing.Image[] bitmaps)
{
int count = 10;
bitmaps = new System.Drawing.Image[count];
Parallel.For(0, count, (i) =>
{
bitmaps[i] = System.Drawing.Image.FromFile("2.bmp");
});
}
If you need out really, don't change the parameter in the lambda expression directly. Instead, use a temporary variable please.
static void test(out System.Drawing.Image[] bitmaps)
{
int count = 10;
System.Drawing.Image[] bitmapsTemp = new System.Drawing.Image[count];
Parallel.For(0, count, (i) =>
{
bitmapsTemp[i] = System.Drawing.Image.FromFile("2.bmp");
});
bitmaps = bitmapsTemp;
}

Categories

Resources