Linq to Objects - Return Pairs of Numbers from List of Numbers

Multicast delegate of type Func (with return value)?

Is it working as intended?

It's working as specified, at least. Whether that's what you intended or not is a different matter :) From section 15.4 of the C# 5 specification - emphasis mine:

Invocation of a delegate instance whose invocation list contains multiple entries proceeds by invoking each of the methods in the invocation list, synchronously, in order. Each method so called is passed the same set of arguments as was given to the delegate instance. If such a delegate invocation includes reference parameters (§10.6.1.2), each method invocation will occur with a reference to the same variable; changes to that variable by one method in the invocation list will be visible to methods further down the invocation list. If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.

Next:

Aren't we losing the return value of the other functions?

Yes, at the moment.

If so, is there a use case in real world of those multicast delegate of functions?

Very rarely, to be honest. However, you can split a multicast delegate apart, using Delegate.GetInvocationList():

foreach (Func<string, string> func in funcSum.GetInvocationList())
{
Console.WriteLine(func("!"));
}

Calling delegate with multiple functions having return values

Actually, with a little bit of trickery and casting, you can get all of the results like this:

var b = new BinaryOp(Add);
b += new BinaryOp(Multiply);

var results = b.GetInvocationList().Select(x => (int)x.DynamicInvoke(2, 3));
foreach (var result in results)
Console.WriteLine(result);

With output:

5
6

Multicast Delegates must have a return type of void. Why?

The premise is wrong; it works fine:

Func<int> func = delegate { Console.WriteLine("first part"); return 5; };
func += delegate { Console.WriteLine("second part"); return 7; };
int result = func();

That is a multicast delegate with a non-void result, working fine. You can see from the console that both parts executed. The result of the last item is the one returned. We can demonstrate that this is a true multicast delegate:

if(func is MulticastDelegate) Console.WriteLine("I'm multicast");

and it will write "I'm multicast" even after just the first line (when there is only a single method listed).

If you need more control over individual results, then use GetInvocationList():

foreach (Func<int> part in func.GetInvocationList())
{
int result = part();
}

which allows you to see each individual result.

In IL terminology:

.class public auto ansi sealed Func<+ TResult>
extends System.MulticastDelegate`

which is to say: Func<T> inherits from MulticastDelegate. Basically, to all intents and purposes, all delegates in .NET are multicast delegates. You might be able to get a non-multicast delegate in managed C++, I don't know. But certainly not from C#.

Delegates with return type multicast gives unexpected result

A combined delegate will only return the result of the last invoked method. From the documentation:

If the delegate has a return value and/or out parameters, it returns
the return value and parameters of the last method invoked

The multicast delegate will still invoke both methods assigned to it. If you change your methods to print the value before returning it, you'll see it clearly:

void Main()
{
string str = "This is a sample string";
strOps obj = new strOps();
strDelegate delRef = obj.removeSpaces;
delRef += strOps.reverseString;

delRef(str);
}

delegate string strDelegate(string str);
class strOps
{
public static string reverseString(string str)
{
string temp = string.Empty;
for(int i=str.Length -1 ; i>=0 ; i--)
{
temp += str[i];
}
Console.WriteLine("Output from ReverseString: {0}", temp);
return temp;

}

public string removeSpaces(string str)
{
string temp = string.Empty;
for (int i = 0; i < str.Length; i++)
{
if (str[i] != ' ')
temp += str[i];
}
Console.WriteLine("Output from RemoveSpaces: {0}", temp);
return temp;
}
}

Outputs:

Output from RemoveSpaces: Thisisasamplestring
Output from ReverseString: gnirts elpmas a si sihT

Can Func return multiple values in C#?

You could say yes, function can return multi values, by Tuple(and ValueTuple) or IEnumerable ect.

but in your example you want to the contrary: run some functions on one value.

where you place new function in the same variable, The first function is run over. also in += in multicasting the return-value return only from the last function.

How I see it:

var listFunctions = new List<System.Func<int, int>>();

listFunctions.Add(x => x * 3);
listFunctions.Add(x => x * 4);

listFunctions.ForEach(x => Console.WriteLine( x(5)));

How to combine the results returned by Multicast Delegates in C#?

You need to cast each function in the invocation list to the delegate type to be able to use the normal function call syntax :

void Main()
{
var sampleMultiDelegate = new SampleMultiDelegate(SayHello);
sampleMultiDelegate += SayGoodbye;
var param1 = "Chiranjib";
string param2;
string result = "";
foreach (var del in sampleMultiDelegate.GetInvocationList())
{
var f = (SampleMultiDelegate)del;
f(param1, out param2);
result += param2 + "\r\n";
}

Console.WriteLine(result);
}

Also fixed the fact that there can't be any result to your delegate calls as they return void.

Multicast Delegate Ambigous

When you have a delegate that has multiple handlers attached to it, you will still get only one return value. There is no direct way to get the other values and naturally you cannot chain the handler functions in a way that the return value of one would be sent to another. The only thing you will get is the last attached handler's return value is returned.

There is no ambiguous behaviour here really, it's just the way it works. If you want to chain the functions you have to use a different approach then a delegate. In this example you could just call the functions and that's it.

Why this multicast delegation isn’t working with functions in C#?

According to the spec:

If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.

If you need more control over individual results, then use GetInvocationList():

foreach (MyDlgt myDlgt in MultiCast.GetInvocationList())
{
double result = myDlgt(NUM1, NUM2);
}

C#:Creating Multicast delegate with boolean return type

public delegate bool Foo(DateTime timestamp);

This is how to declare a delegate with the signature you describe. All delegates are potentially multicast, they simply require initialization. Such as:

public bool IsGreaterThanNow(DateTime timestamp)
{
return DateTime.Now < timestamp;
}

public bool IsLessThanNow(DateTime timestamp)
{
return DateTime.Now > timestamp;
}

Foo f1 = IsGreaterThanNow;
Foo f2 = IsLessThanNow;
Foo fAll = f1 + f2;

Calling fAll, in this case would call both IsGreaterThanNow() and IsLessThanNow().

What this doesn't do is give you access to each return value. All you get is the last value returned. If you want to retrieve each and every value, you'll have to handle the multicasting manually like so:

List<bool> returnValues = new List<bool>();
foreach(Foo f in fAll.GetInvocationList())
{
returnValues.Add(f(timestamp));
}

Adding multiple delegates to FuncT and returning result of first lambda delegate (C#)?

Why not use the traditional delegate syntax, and then get the invocation list explicitly? For example:

delegate int fdelegate();

var f1 = new Func<int>(() => { return 1; });
var f2 = new Func<int>(() => { return 2; });

var f1d = new fdelegate(f1);
var f2d = new fdelegate(f2);
fdelegate f = f1d;
f += f2d;

int returnValue;
bool first = true;
foreach (var x in f.GetInvocationList())
{
if (first)
{
returnValue = ((fdelegate)x)();
first = false;
}
else
{
((fdelegate)x)();
}
}


Related Topics



Leave a reply



Submit