Siddhant Rimal
Siddhant Rimal

Reputation: 978

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:

  1. 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.
  2. This answer has what I need but for the life of me, I couldn't make it work for my specific purpose.

Problem Breakdown

which means, in my Main Program, I will be using autowordwrap(somestring, newline()); or autowordwrap(somestring, sameline()); wherever necessary!

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

Upvotes: 1

Views: 795

Answers (3)

Amit
Amit

Reputation: 46323

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.

Upvotes: 1

Steve Cooper
Steve Cooper

Reputation: 21480

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.

Upvotes: 3

Ehsan Sajjad
Ehsan Sajjad

Reputation: 62488

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);

Upvotes: 3

Related Questions