在 C# 中使用委托重载方法

Overloading a method with delegates in c#

有什么方法可以 "overload" 使用委托的函数吗?我想要一个系统,我可以在构造函数中传递匿名函数并将其保存在成员变量中。数据类型并不是真正的问题,但传递的函数可以有一个或两个参数。我试过在委托定义中使用 (params double[] vals),但这会使传递的匿名函数复杂化,并允许使用比应允许的更多的参数。

所以我创建了两个空方法来保存这两种类型。例如:

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
    }

}

最终,我想做的更像这样:

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
    }

}

我对 C# 不是很熟悉,但是肯定有一种方法可以做这样的事情,而不必定义一个委托的实例或另一个将不被使用的实例。

.Net 提供了一些开箱即用的有用委托类型;即 Action 用于返回 void 的方法,Func 用于保留参数。这些提供了匿名委托的类型安全,并提供了一种干净的方法来满足您的需要,这似乎类似于命令或策略模式。

您还可以使用表达式来声明内联委托,如下所示:

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

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

=> 本质上意味着 'into',如果你有参数,你会在箭头之前声明它们:

(arg1, arg2) => ...

在现代 .Net 编码中,表达式和 Action/Func 几乎完全取代了匿名委托。

如果您在 class 上有一个 属性 类型的 Action,您可以直接将其作为方法调用。

public Action Calc { get; set; }

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

Calc();

这对你有帮助。在这里,我刚刚将您的 calc 变量初始化为对象,它是所有类型(int、class、委托等)的基本类型,并且在评估方法中我将它从对象转换为适当的类型。

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
    }

}

我会把我的帽子扔进戒指...

以下是您将如何使用 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
    }

}

请注意,我从调用中删除了 "o",并且我使用转换来选择正确的操作(并检查是否提供了正确数量的操作数)。