Delegate instances vs passing function directly - c#

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.

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.

Store methods in an array and call them in C#

In javascript we can do this:
var arr = [];
function fooBar() {
console.log('Hello World');
}
arr[0] = fooBar;
arr[0]();
Essentially each function is a real object and I can store them in an array if I want to. My question is, since C# doesnt have pointers, what is the best way to handle such as scenario? I mean how can I store function references into arrays?
I know we have something called delegates but im not sure if this is the right thing for the task...
Delegates are exactly what you need:
var list = new List<Action>();
...
void fooBar() {
....
}
...
list.Add(fooBar);
The Action is actually nothing but a delegate, simply look its definiton and you´ll see it is similar to a delegate expecting nothing and returning nothing. If you want to pass parameters use any of it´s generic versions, for example Action<T>. If you also need to add methods that return something use the Func-delegate instead.
EDIT: Every delegate has its own type so you can´t mix them and put them alltogether into one single collection, except you use a collection of type Delegate:
var list = new List<Delegate>();
In this case you can´t use urual braces to call the actual delegate, instead you have to use DynamicInvoke and pass the arguments according to the delegates signature.
list[0].DynamicInvoke(args);
Delegates are the right thing for the task - they're equivalent to a strongly-typed function pointer.
Because each delegate is its own type you cannot mix-and-match different delegate types in an array type to a single delegate-type, you can use the parent System.Delegate to allow you to store delegates of different types in the array, though you lose the ability to invoke them directly without some side-channel that informs your program of their arguments.
For example:
public static String Meow(Cat cat) { return "meow"; }
public static String Purr(Cat cat) { return "purr"; }
delegate String CatSound(Cat cat);
CatSound[] catSounds = new CatSound[] {
Meow,
Purr
};
You can then invoke them directly:
Cat orion = new Cat();
catSounds[0]( orion ); // meow
catSounds[1]( orion ); // purr
If you want to add a DogSound delegate to your collection, you'll have a harder job: you need to use Delegate[] instead...
delegate String DogSound(Dog dog);
Delegate[] petSounds = new Delegate[] {
new CatSound( Meow ),
new CatSound( Purr ),
new DogSound( Woof ),
new DogSound( Bark ),
}; // note that C# compiler allows shorthand syntax where simply `Meow` is behind-the-scenes converted into `new CatSound( Meow )`.
...and you have to invoke it using the DynamicInvoke method ( https://msdn.microsoft.com/en-us/library/system.delegate.dynamicinvoke(v=vs.110).aspx ) which means you'll lose compile-time verification of correct arguments, instead any call made with incorrect arguments will fail at runtime with a MemberAccessException.
Dog pupper = new Dog();
Cat orion = new Cat();
petSounds[0].DynamicInvoke( orion );
petSounds[1].DynamicInvoke( orion );
petSounds[2].DynamicInvoke( pupper ); // ok, this is a DogSound
petSounds[3].DynamicInvoke( orion ); // this will fail at runtime because you're passing a Cat into a DogSound delegate
You can also think of delgates as "an interface for a single method".
Prior to the .NET Framework 3.5, you generally needed to define your own delegate types using the delegate keyword (note that the delegate keyword is also overloaded for anonymous functions in C# 3.0), however there is now System.Action and System.Func which serve 95% of cases where you would have previously needed to define your own type. Indeed, today my delegate CatSound is unnecessary, you could just use Func<Cat,String> instead.
Given that the functions to call have the same signature, it could be done by using the predefined generics for delegates as follows.
Func<int,int> Square = x => x*x;
Func<int,int> Successor = x => x+1;
Func<int,int> Functions[] = new Func<int,int>[]{ Square, Successor };
int A = Functions[0](2); // A gets assigned 4;
int B = Functions[1](1); // B gets assigned 2;
You could Store Action or Func objects, someting like:
void Main()
{
var arr = new object[2];
arr[0] = 1;
arr[1] = (Action)DoIt;
foreach (var a in arr)
{
if (a is Action)
{
((Action)a)();
}
else
{
Console.WriteLine(a.ToString());
}
}
}
public void DoIt()
{
Console.WriteLine("did");
}
Consider actions (depending on .net verion)
https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx
List<Action<string>> actions = new List<Action<string>>();
actions.Add(() => {
//do stuff
});
or if you need rturn values use Func: https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx
yea through delegates you can:
static void iammain()
{
List<Action> lst = new List<Action>();
lst.AddRange(new Action[] { proc1, proc2, proc3 });
for (int i = 0; i < lst.Count; i++)
{
lst[i]();
}
}
static void proc1()
{
Console.WriteLine("i am proc1");
}
static void proc2()
{
Console.WriteLine("i am proc2");
}
static void proc3()
{
Console.WriteLine("i am proc3");
}

C# Pass method with arguments as a parameter to Lazy<T>

Let's consider this code:
public void DoSomething<T>(Func<T> MyFunc)
{
var NewLazyItem = new Lazy<T>(MyFunc);
// do stuff
// use the NewLazyItem
}
And let's say I have a method like this:
public int Add(int a, int b) { return a + b; }
What I would like to achieve is to be able to pass the Add method to the DoSomething method but with parameters along.
Ideally I could pass Add, 2 and 3 and when the NewLazy item gets used, Add(2, 3) gets called.
I tried various ideas, but I can't find a way to make it work.
Unless I'm misunderstanding the question, the simplest way is just to include the parameters as closures for a lambda expression:
var x = 2;
var y = 3;
DoSomething(() => Add(x, y));

Get result from Delegate Invocation list

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

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