0

Is there some way I can "overload" a function using delegates? I'd like to have a system in place wherein I can pass an anonymous function in a constructor and save it in a member variable. Data type isn't really an issue, but the passed functions can have one or two parameters. I've tried using (params double[] vals) in the delegate definition, but that complicates the passed anonymous functions and allows more parameters than should be allowed.

So I've created two empty methods to hold the two types. As an example:

public class OpWrapper
{
    public int operands;      //the number of operands this operator needs.
    public int precedence;    //the precedence this operator gets when calculating.
    public bool rightAssoc;   //whether or not this operator is right associative (true) or left associative (false).

    public delegate double evalDelegate(double a, double b);
    public delegate double calcDelegate(double a);
    public evalDelegate eval; //method used for two value inputs. Assigned in constructor.
    public calcDelegate calc; //method used for single value input. Assigned in constructor.

    //constructor initializes all variables.
    public OpWrapper(int o, int p, evalDelegate f, bool a = false)
    {
        operands = o;
        precedence = p;
        rightAssoc = a;
        eval = new evalDelegate(f);
    }
    //overloaded constructor assigns the proper method.
    public OpWrapper(int o, int p, calcDelegate f, bool a = false)
    {
        operands = o;
        precedence = p;
        rightAssoc = a;
        calc = new calcDelegate(f);
    }

    public double evaluate(params double[] values)
    {
        //do stuff
        if (operands == 1)
        {
            return calc(values[0]);
        }
        else
        {
            return eval(values[0], values[1]);
        }
        //more stuff
    }

}

Ultimately, what I'd like to do is more like this:

public class OpWrapper
{
    public int operands;      //the number of operands this operator needs.
    public int precedence;    //the precedence this operator gets when calculating.
    public bool rightAssoc;   //whether or not this operator is right associative (true) or left associative (false).

    public delegate double evalDelegate(double a, double b);
    public delegate double calcDelegate(double a);
    public ???????? calc; //method that does the passed function.

    //constructor initializes all variables.
    public OpWrapper(int o, int p, evalDelegate f, bool a = false)
    {
        operands = o;
        precedence = p;
        rightAssoc = a;
        eval = new evalDelegate(f);
    }
    //overloaded constructor assigns the proper method.
    public OpWrapper(int o, int p, calcDelegate f, bool a = false)
    {
        operands = o;
        precedence = p;
        rightAssoc = a;
        calc = new calcDelegate(f);
    }

    public double evaluate(params double[] values)
    {
        //do stuff
        if (operands == 1)
        {
            return calc(values[0]);
        }
        else
        {
            return calc(values[0], values[1]);
        }
        //more stuff
    }

}

I'm not tremendously familiar with C#, yet, but surely there is a way to do something like this without having to define an instance of one delegate or the other that will just go unused.

  • You should use Action if you don't need a return value or Func if you do. These replace the classic delegate so there is no need to create delegate signatures. – Jacob Roberts Apr 21 '15 at 20:48
  • Looks like you are trying to do something that could be achieved easier using expressions. But its not fully clear what that "something" is. – Alex Apr 21 '15 at 20:53
  • do you know what a delegate is ? think of it like this .. `A Delegate is like a placeholder for Methods` do a google search on Delegates since you are not tremendously familiar with C# as you have stated.. are you familiar with `GOOGLE` come on now – MethodMan Apr 21 '15 at 20:56
  • @Jacob: Noted. I started out using Func<>, but they got switched out when I tried using params double[] as a parameter and discovered Func and params don't like each other. – pucedragonlord Apr 21 '15 at 20:58
  • @Alex: This example is just something I'm doing to learn some of the nuances of c#. It's basically just a wrapper for expressions, which it puts together and evaluates from reverse Polish Notation. – pucedragonlord Apr 21 '15 at 21:07
  • @MethodMan: I'm aware delegates are placeholders for methods. They work delightfully in that regard, but that doesn't exactly help the question, now, does it? Especially since I do know you can't overload delegates, either. – pucedragonlord Apr 21 '15 at 21:07
  • here is some good reading for you on the same subject maybe you will see other alternatives to use in your case.. happy coding http://stackoverflow.com/questions/17028283/can-i-define-2-delegates-with-the-same-name-but-different-parameters – MethodMan Apr 21 '15 at 21:13

3 Answers3

1

.Net provides some useful delegate types out of the box; namely Action for a void returning method and Func for one retaining an argument. These provide type safety over anonymous delegates and provide a clean approach to what you need which appears to be something like the Command or the Strategy pattern.

You can also use expressions to declare delegates inline as follows:

public void InvokeAction(Action invoke)
{
    invoke();
}

InvokeAction(() => Console.WriteLine(...));

=> essentially means 'into' and if you had arguments you would declare them before the arrow:

(arg1, arg2) => ...

Expressions and Action/Func have all but taken over from anonymous delegates in modern .Net coding.

If you have a property of type Action on a class you call it as a method directly.

public Action Calc { get; set; }

Calc = () => Console.WriteLine(...);

Calc();
James Lucas
  • 2,452
  • 10
  • 15
  • Also noted. I do use the => notation in constructor calls to actually hand the methods over. These do return something, though, so Action won't work. I tried defining a public Func calc, but got an error about Func needing a million parameters. Unfortunately, just doing public Func calc and public Func calc yells at you for having two things named calc, which was disappointing. – pucedragonlord Apr 21 '15 at 21:13
  • Yes you can overload methods not properties. But maybe a different name for each is a good design choice anyway. If they take different parameters then they perform different tasks I would assume? – James Lucas Apr 21 '15 at 21:16
1

this will help you. In this i have just initialise your calc variable as object which is base type of all types (int,class,delegates etc) and in evaluate method i have cast it from object to its appropriate type.

public class OpWrapper
{
    public int operands;      //the number of operands this operator needs.
    public int precedence;    //the precedence this operator gets when calculating.
    public bool rightAssoc;   //whether or not this operator is right associative (true) or left associative (false).

    public delegate double evalDelegate(double a, double b);
    public delegate double calcDelegate(double a);
    public object calc; //method that does the passed function.

    //constructor initializes all variables.
    public OpWrapper(int o, int p, evalDelegate f, bool a = false)
    {
        operands = o;
        precedence = p;
        rightAssoc = a;
        calc = new evalDelegate(f);
    }
    //overloaded constructor assigns the proper method.
    public OpWrapper(int o, int p, calcDelegate f, bool a = false)
    {
        operands = o;
        precedence = p;
        rightAssoc = a;
        calc = new calcDelegate(f);
    }

    public double evaluate(params double[] values)
    {
        //do stuff
        if (operands == 1)
        {
            return (calc as calcDelegate)(values[0]);
        }
        else
        {
            return (calc as evalDelegate)(values[0], values[1]);
        }
        //more stuff
    }

}
hsCode
  • 469
  • 4
  • 11
  • delegates are function pointer and it can't be overloaded because there's not any body for delegates, it just has the return type & input parameter (say as signature). – hsCode Apr 21 '15 at 21:13
1

I'll throw my hat into the ring...

Here is how you would use a Func.

public class OpWrapper
{
    public int operands;      //the number of operands this operator needs.
    public int precedence;    //the precedence this operator gets when calculating.
    public bool rightAssoc;   //whether or not this operator is right associative (true) or left associative (false).

    public object func;

    //constructor initializes all variables.
    public OpWrapper(int p, Func<double, double> f, bool a = false)
    {
        //No need to pass in o, we can infer from context that its a single parameter
        operands = 1;
        precedence = p;
        rightAssoc = a;
        func = f;
    }
    //overloaded constructor assigns the proper method.
    public OpWrapper(int p, Func<double, double, double> f, bool a = false)
    {
        //No need to pass in o, we can infer from context that its a double parameter
        operands = 2;
        precedence = p;
        rightAssoc = a;
        func = f;
    }

    public double evaluate(params double[] values)
    {
        if (values.Length != operands)
            throw new InvalidOperationException("Invalid number of operands");

        //do stuff
        if (operands == 1)
        {
            return ((Func<double, double>)func)(values[0]);
        }
        else
        {
            return ((Func<double, double, double>)func)(values[0], values[1]);
        }
        //more stuff
    }

}

Note that I removed "o" from the call, and that I used casting to choose the right operation (and checked if the proper number of operands was provided).

Ron Beyer
  • 11,003
  • 1
  • 19
  • 37
  • That's it! I actually tried "public object" earlier, but I didn't think to cast it like that in evaluate. C# has a lot more casting than I'm used to. Python and its amorphous variables have spoiled me. – pucedragonlord Apr 21 '15 at 21:18
  • Just note, there is a performance cost to casting. You really should have two distinct types for unary and binary operators that derive from a base class. This is a fundamental design principle called "Separation of Concerns" and will keep your code a lot neater. – Ron Beyer Apr 21 '15 at 21:20
  • Were this anything more than a quick and dirty project, I probably would have started with that, but this little problem has let to quite the learning experience. Thanks for the insight. – pucedragonlord Apr 22 '15 at 14:31