【问题标题】:Overloading a method with delegates in c#在 C# 中使用委托重载方法
【发布时间】:2015-04-21 20:43:14
【问题描述】:

有什么方法可以使用委托“重载”函数吗?我想有一个系统,我可以在构造函数中传递一个匿名函数并将其保存在成员变量中。数据类型并不是真正的问题,但传递的函数可以有一个或两个参数。我尝试在委托定义中使用 (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# 还不是很熟悉,但肯定有一种方法可以做这样的事情,而不必定义一个委托的实例,或者另一个不使用的委托实例。

【问题讨论】:

  • 如果你不需要返回值,你应该使用 Action,如果你需要,你应该使用 Func。这些替换了经典委托,因此无需创建委托签名。
  • 看起来您正在尝试做一些可以使用表达式更容易实现的事情。但它并不完全清楚那个“东西”是什么。
  • 你知道代表是什么吗?像这样想.. A Delegate is like a placeholder for Methods 在 Delegates 上进行谷歌搜索,因为您对 C# 不是很熟悉,正如您所说.. 您熟悉 GOOGLE 现在来吧
  • @Jacob:注意到了。我开始使用 Func,但是当我尝试使用 params double[] 作为参数并发现 Func 和 params 彼此不喜欢时,它们被切换了。
  • @Alex:这个例子只是我为了学习 c# 的一些细微差别而正在做的事情。它基本上只是一个表达式的包装器,它将它们放在一起并从反向波兰表示法进行评估。

标签: c# .net delegates overloading


【解决方案1】:

我会把我的帽子扔进擂台......

下面是你将如何使用 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”,并且我使用强制转换来选择正确的操作(并检查是否提供了正确数量的操作数)。

【讨论】:

  • 就是这样!我之前实际上尝试过“公共对象”,但我没想到在评估中像那样投射它。 C# 的转换比我习惯的要多得多。 Python 和它的无定形变量把我宠坏了。
  • 请注意,强制转换有性能成本。对于从基类派生的一元和二元运算符,您确实应该有两种不同的类型。这是一个称为“关注点分离”的基本设计原则,可以让您的代码更加整洁。
  • 如果这不仅仅是一个快速而肮脏的项目,我可能会从这个开始,但是这个小问题已经让学习体验变得非常糟糕。感谢您的洞察力。
【解决方案2】:

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

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

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

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

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

(arg1, arg2) => ...

Expressions 和 Action/Func 在现代 .Net 编码中几乎已经从匿名委托中接管了。

如果你在一个类上有一个 Action 类型的属性,你可以直接把它作为一个方法来调用。

public Action Calc { get; set; }

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

Calc();

【讨论】:

  • 也注意到了。我确实在构造函数调用中使用 => 表示法来实际移交方法。但是,这些确实会返回一些东西,因此 Action 将不起作用。我尝试定义一个公共 Func calc,但收到有关 Func 需要一百万个参数的错误。不幸的是,只做 public Func calc 和 public Func calc 会因为有两个名为 calc 的东西而对你大喊大叫,这令人失望。
  • 是的,你可以重载方法而不是属性。但也许每个不同的名称无论如何都是一个不错的设计选择。如果他们采用不同的参数,那么他们会执行不同的任务吗?
【解决方案3】:

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

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
    }

}

【讨论】:

  • 委托是函数指针,它不能被重载,因为委托没有任何主体,它只有返回类型和输入参数(比如签名)。
猜你喜欢
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-02
  • 1970-01-01
相关资源
最近更新 更多