ForEach extension method - c#

I'm a bit confused over a line of code:
Enumerable.Range(1,10).ToList().ForEach(Console.WriteLine);
This line does what it says it does, it prints out each number from 1 to 10 with a line break inbetween each of them, all that with one neat little line of code..
Now I'm only a C# novice at best, but it looks completely foreign to me, how can we call Console.WriteLine() without providing it with any arguments? How does it know what it's going to print? From this syntax it's not even clear to me that we're calling on a method (considering the lack of paranthesis around WriteLine).
I'm assuming that there's a lot of stuff going on "behind the scenes" here but I'm not very good at reading IL code, from what I've gathered reading the MSIL it seems like ForEach calls a generic delegate(System.Action) on each element in the collection, I am guessing that it then passes the element as an argument to the System.Action delegate but that's only my guess..

There is an implicit conversion from a method group (Console.WriteLine in this case) and a compatible delegate type. You code is effectively the same as
Action<int> f = Console.WriteLine;
Enumerable.Range(1,10).ToList().ForEach(f);
The delegate f is compatible with the method void Console.WriteLine(int)

Enumerable.Range(1,10).ToList().ForEach(Console.WriteLine)
is short for
Enumerable.Range(1,10).ToList().ForEach(text => Console.WriteLine(text));
it is called a MethodGroup

Foreach statement is a generic one, and in your case it is a ForEach<int>. It takes one argument of type Action<int> and any void method accepting single int parameter will work for this purpose. Console.WriteLine is one of such methods

Related

Passing a Delegate[] to a method

I am trying to desconstruct a method written by another coder to see how it works but it's getting a bit confusing
We have a Delegate that takes an Action as parameter.
private delegate void FunctionDelegate(Action next);
A function is then called in the constructor that takes an array of these delegates as parameter and executes each value in the array
LoadInSeries(LoadRoleAreaHours, LoadTableData);
The Function looks like this
private void LoadInSeries(params FunctionDelegate[] _delegates)
{
var Delegates = new List<FunctionDelegate>(_delegates);
Func<Action, Action> creator = null;
creator = delegate(Action inner)
{
if (Delegates.Count > 0)
{
FunctionDelegate L = Delegates.First();
Delegates.RemoveAt(0);
Action next = delegate { L(inner); };
return creator(next);
}
else return inner;
};
Action outer = creator(null);
if (outer != null)
outer();
}
The intent was too chain a series of functions with each function calling the next but wouldnt it just be easy to use a multicast delegate and add each function to the invocation list.
Does this code do something different?
Without a good Minimal, Complete, and Verifiable code example, it's impossible to understand the code fully. Of most significant concern is that your code example includes a mysterious L() method, the behavior of which we have no idea. There is also the problem with the FunctionDelegate = Delegates.First(); statement. At best, the FunctionDelegate identifier refers to a class field or property; at worst, that statement won't even compile. Either way, there's no evidence that the delegate object being removed from the input list is ever actually invoked.
So to even answer the question, some basic assumptions have to be made, which may or may not be correct.
That said, in the best-case scenario — which is that the code has hidden some awful, convoluted mechanism in the L() method that ultimately winds up able to invoke the delegate for the current call to the creator delegate — the code you're looking at is not simply invoking delegates in sequence, as would be the case with a MulticastDelegate. Rather, the code is constructing a chain of calls to the L() method, passing each delegate instance to the method in sequence.
Since you didn't show us the L() method, there's no way to say what the code actually does. I would agree that if all that L() does is invoke the delegate you pass to it, then this code looks like a very complicated way to just invoke an array of delegates. But, giving the benefit of the doubt to the person who wrote the code, this simply means that L() probably does something other than simply invoke the delegate.
Of course, it's possible the author of the code doesn't deserve the benefit of the doubt. In that case, not only would it be simpler to just use a multicast delegate, the simplest implementation would just iterate over the array, invoking each delegate in the desired sequence. But I say that without really knowing what the code does. I'm just assuming it's intended to do something useful with the delegates that are passed to it. There's no evidence in the code you posted to support even that generous assumption.
Give us the full picture, and a more definitive answer can be provided. Without knowing what L() is, or what side effects might exist in the passed-in delegates' target methods, it's impossible to say for sure whether the code you're looking at really needs to be written that way or not.

C# - take method as an argument without specifying args

I have a method that needs to take the function and its owner class as the input arguments and then to proceed with its names with reflection. Of course I could take a couple of strings as the input args, so the method would look like this:
void Proceed(string className, string methodName)
{
Console.WriteLine($"{className}.{methodName} called");
//...
}
and would be called like this:
Proceed(nameof(Foo), nameof(Foo.Bar));
But I wonder if there is any way to avoid writing the nameof keyword every time I am trying to call the method. To me something like Proceed<Foo>(f => f.Bar) would look a lot nicer.
I suppose this could be solved with expressions. The problem I face is that if method Bar has arguments, you have to specify them explicitly when calling the method (which seems excessive in my case where you only going to need the name of the method later).
So, the best solution I managed to find is this one:
void Proceed<T>(Expression<Func<T, Action<object, object>>> expression)
{
//...
}
Yet it still specifies the argument method's signature in its own args and therefore is not generic enough.
I wonder if there is some way to pass the function as an argument without specifying its arguments (provided I am only going to need its name later, just like nameof keyword does).
I think you are looking for the usage of an event or delegate.
You can look up more information regarding those 2 online. The idea is that they store some methods with the same arguments so that later it knows what kind of arguments you need to call.
Yes, use the Delegate keyword.
See the answer here.

way to define functions in parameters in order to pass one, out of two, functions as an argument

My program had a simple function newline() that would provide an int value to a int variable x.
public void autowordwrap(string wrapthisword)
{
//some code that does things irrelevant to this problem, with the string
x=newline();
//assume x is already declared properly
//do something with value from x
}
Problem started when I introduced a new function sameline()
I want to be able to do any one of these conveniently, at a time:
public void autowordwrap(string wrapthisword)
{
x=newline();
}
or,
public void autowordwrap(string wrapthisword)
{
x=sameline();
}
So, I thought of trying this:
public void autowordwrap(string wrapthisword, Func<void,int> linefunc)
{
x=linefunc;
}
which I can later call on requirement as:
autowordwrap(mystring,newline());
or,
autowordwrap(mystring,sameline());
But it is not quite working out for me!
It says keyword 'void' cannot be used in this context
Problem is:
What I want to do should be simple enough but I'm not quite understanding how it works. I understand that Action<> works for functions without return type and Func<> works for function with a return type.[Reference-1].
What I've gathered so far is:
MSDN tells me: To reference a method that has no parameters and returns void (or in Visual Basic, that is declared as a Sub rather than as a Function), use the Action delegate instead.
Since my newline() function is defined as an int-datatype, and it returns an integer after running, I thought Action<> didn't suit my needs.
This answer has what I need but for the life of me, I couldn't make it work for my specific purpose.
Problem Breakdown
I have two functions newline() and sameline()
I wish to pass any ONE out of the TWO of them as an argument of the function autowordwrap()
which means, in my Main Program, I will be using autowordwrap(somestring, newline()); or autowordwrap(somestring, sameline()); wherever necessary!
both newline() and sameline() are int-datatype functions who return integer value upon being called. For the sake of this problem, lets store it in int x
while trying to solve this, I'm assuming that using Func is used to pass nothing onto the function as an argument while calling example: newline(void) and the int part is used to define the function newline() or any function represented by delegate Func<> as one which returns an int value.
I have realized that what I have seemed to learn must be fundamentally flawed somehow somewhere. Please enlighten me. Reference links would be very helpful too.
Solving this problem in any way is acceptable. You do not need to do this in the way that I may have unintentionally rigidly outlined. Please feel free to explore creative solutions as long as they fulfill the intended purpose in C#
Yes, I acknowledge that THIS is a possible duplicate of this question but I couldn't make much sense of the helpful answer posted over there. Assuming, this will be the case for many future readers, I'm making this question and linking it to that question so that it may be helpful to people who'll face this same problem in the future.
Endnote:
This Question has been solved! The marked answer lays down the way for doing this and there is also some great explanation in the answers. If you are facing some errors while solving a similar question of this nature, you might be able to fix those my looking over screenshots of my own errors. They're here in the revision section no.4
Func<T> has to return some thing, it cannot be void, you have to use Action<T>, if you don't want to return anything.
and if you don't want to pass any input argument to the Func<T>, then you just need one parameter which is return type like:
Func<int> linefunc
you cannot define input type parameter for Func<T,TResult> as void, instead of that just remove the input type parameter of it,
your method definition would look like :
public void autowordwrap(string wrapthisword, Func<int> linefunc)
{
x=linefunc();
}
and call it like:
autowordwrap(mystring, newline);
autowordwrap(mystring, sameline);
You're very nearly there. There are a couple of issues.
First, from your code you appear to be passing the result of your functions in;
autowordwrap("foo", newline());
In this code, C# will invoke the newline function, getting a result. It will then pass the result of that function -- your int -- as the second parameter to autowordwrap.
What you're wanting to do is pass in the un-invoked function itself;
autowordwrap("foo", newline);
So long as the signature of the newline function is compatible with the signature required by autowordwrap, you'll be able to invoke that function inside autowordwrap.
The second part isn't so much the difference between Func<> and Action<>, but about the generic parameters.
The signature you want is a function which takes no parameters and returns an int. So it's reasonable to try
Func<void, int>
but actually, Func<> can take any number of generic types. All but the last are parameters; the last is the return value. So
Func<string, string, int>
corresponds to a method like
public int MyFunction(string s1, string s2) { return 0; }
What you're trying for is a function of no parameters, equivalent to
public int MyFunction() { reutrn 0; }
So the signature you're looking for is
Func<int>
That is, a function of no parameters, returning int. For clarity,
Action<int>
takes one integer parameter and reutrns nothing, equivalent to
public void MyAction(int myParam) { }
--
Oh, and to clarify;
Func<void, int>
Doesn't work because it's equivalent to writing this in C#
public int MyFunction(void x) {}
which is like saying 'a function which takes one parameter, which is a variable of type 'void''. That doesn't make sense, hence the compiler error.
Since your function doesn't need a delegate, it needs an int, you're better off avoiding delegates altogether, just pass the int value, and do this:
public void autowordwrap(string wrapthisword, int separator)
{
//some code that does things irrelevant to this problem, with the string
// if you need it in "x"
x=separator;
//do something with value from x
}
autowordwrap(mystring,newline());
// or
autowordwrap(mystring,sameline());
The general idea for creating clean high quality code is for a function to accept the value(s) it requires to do its specific task, and not some complex input that is "bigger" then that.

"Ternary" operator for different method signatures

I'm looking for an elegant way to choose a method signature (overloaded) and pass an argument based on a conditional. I have an importer that will either produce the most recent file to import, or take an explicit path for the data.
Currently my code looks like this:
if (string.IsNullOrEmpty(arguments.File))
{
importer.StartImport();
}
else
{
importer.StartImport(arguments.File);
}
I would like it to look like this (or conceptually similar):
importer.StartImport(string.IsNullOrEmpty(arguments.File) ? Nothing : arguments.File);
The idea being that a different method signature would be called. A few stipulations:
1) I will not rely on 'null' to indicate an unspecified file (i.e. anything besides null itself).
2) I will not pass the arguments struct to the importer class; that violates the single responsibility principle.
One solution I'm aware of, is having only one StartImport() method that takes a single string, at which point that method resolves the conditional and chooses how to proceed. I'm currently choosing to avoid this solution because it only moves the if-statement from one method to another. I'm asking this question because:
1) I would like to reduce "8 lines" of code to 1.
2) I'm genuinely curious if C# is capable of something like this.
I would like to reduce "8 lines" of code to 1.
I think you're asking the wrong question. It's not how many lines of code you have, it's how clear, maintainable, and debuggable they are. From what you've described, importing from a default location and importing with a known file are semantically different - so I think you're correct in separating them as two different overloads. In fact, you may want to go further and actually name them differently to further clarify the difference.
I'm genuinely curious if C# is capable of something like this.
Sure, we can use all sorts of fancy language tricks to make this more compact ... but I don't think they make the code more clear. For instance:
// build a Action delegate based on the argument...
Action importAction = string.IsNullOrEmpty(arguments.File)
? () => importer.StartImport()
: () => importer.StartImport(arguments.File)
importAction(); // invoke the delegate...
The code above uses a lambda + closure to create a Action delegate of the right type, which is then invoked. But this is hardly more clear ... it's also slightly less efficient, as it requires creating a delegate and then invoking the method through that delegate. In most cases the performance overhead is completely negligible. The real problem here is the use of the closure - it's very easy to misuse code with closures - and it's entirely possible to introduce bugs by using closures incorrectly.
You can't do this using 'strong-typed' C#. Overload resolution is performed at compile time: the compiler will work out the static (compile-time) type of the argument, and resolve based on that. If you want to use one of two different overloads, you have to perform two different calls.
In some cases, you can defer overload resolution until runtime using the dynamic type. However, this has a performance (and clarity!) cost, and won't work in your situation because you need to pass a different number of arguments in the two cases.
Yes, it is possible (using reflection). But I wouldn't recommend it at all because you end up with way more code than you had before. The "8-lines" which you have are quite simple and readable. The "one-liner" using reflection is not. But for completeness sake, here's a one-liner:
importer.GetType().GetMethod("StartImport", string.IsNullOrEmpty(arguments.File) ? new Type[0] : new Type[] { typeof(string) }).Invoke(importer, string.IsNullOrEmpty(arguments.File) ? new object[0] : new object[] { arguments.File) }));
Frankly, I think your code would be a lot more readable and modular if you combined the overloaded methods back into a single method and moved the conditional inside it instead of making the caller pre-validate the input.
importer.StartImport(arguments.File);
void StartImport(string File) {
if (string.isNullOrEmpty(File)) {
...
}
else {
...
}
}
Assuming you call the method from multiple places in your code you don't have the conditional OR ternary expression scattered around violating the DRY principle with this approach.
//one line
if (string.IsNullOrEmpty(arguments.File)) {importer.StartImport();} else{importer.StartImport(arguments.File);}

C# method group strangeness

I discovered something very strange that I'm hoping to better understand.
var all = new List<int[]>{
new int[]{1,2,3},
new int[]{4,5,6},
new int[]{7,8,9}
};
all.ForEach(n => n.ForEach(i => Console.WriteLine(i)));
which can be rewritten as:
...
all.ForEach(n => n.ForEach(Console.WriteLine));
How is it possible to leave out the lambda expression parameter (i=>) and still have the current item passed to console.WriteLine?
Thanks for any insight.
-Keith
List<T>.ForEach is looking for an Action<T>. When you write
n.ForEach(Console.WriteLine);
what you have here is one of the members of the method group Console.WriteLine playing the role of an Action<T>. The compiler will look for the best overload of Console.WriteLine that eats instances of int. In fact, it will use the overload Console.WriteLine(int). It will then use this overload to play the role of an Action<int>.
For details on how this is done, see §6.6 of the specification (Method group conversions).
However, when you write
n.ForEach(i => Console.WriteLine(i));
we actually have a very different Action<int> In the first case, the Action<int> was Console.WriteLine(int). Here, the Action<int> is equivalent to you having written
public static void DoSomething(int i) {
Console.WriteLine(i);
}
and then
n.ForEach(DoSomething);
(Of course, the compiler has to go through the same method group process as described above to figure out what is meant by DoSomething).
The point is that in the first case the Action<int> is Console.WriteLine(int). However, in the second case the Action<int> is a middle man (the lambda expression) that itself will call Console.WriteLine(int).
This is less confusing if you consider what is really happening.
You are passing a method to a delegate argument. Most of the time, we think of delegates in the context of events, but they can be parameters to methods as well. It doesn't seem odd when a method is added to an event without arguments, it just is unusual looking when executed in this context.
Before lambdas, you had to do this all the time, and it was such a pain that one would never consider using a library that looked like LINQ. With Lambdas, this is easier to do, but you can always do the old way as well.

Categories

Resources