我是否以有用的方式使用 C# 委托?
Am I using C# delegates in a useful way?
我正在使用 C# 中的委托做一个简单的练习。基本前提是它只是简单地执行加法和减法等计算。
public class Calculator
{
public static int Add(int num1, int num2)
{
return num1 + num2;
}
public static int Multiply(int num1, int num2)
{
return num1 * num2;
}
public static int Subtract(int num1, int num2)
{
return num1 - num2;
}
}
并且我创建了一个委托,它将在另一个 class 中调用这些函数。
public delegate int CalculatorDelegate(int num1, int num2);
实现 class 如下所示:
public class Calculation
{
public int PerformCalculation(int choice, int number1, int number2)
{
CalculatorDelegate cd;
if (choice == 1)
{
cd = Calculator.Add;
return cd(number1, number2);
}
else if (choice == 2)
{
cd = Calculator.Subtract;
return cd(number1, number2);
}
else if (choice == 3)
{
cd = Calculator.Multiply;
return cd(number1, number2);
}
else
{
cd = Calculator.Add;
return cd(number1, number2);
}
}
}
让我对委托感到困惑的是为什么不直接执行以下操作?
if (choice == 1)
{
return Calculator.Add(number1,number2);
}
我认为我的困惑是围绕着这样一个事实:如果这些方法已经是静态的,那么即使对它们进行委托又有什么意义呢。我可以简单地将它们称为静态方法。如果我尝试使这些方法成为非静态方法,那么我不能让我的委托在另一个 class 中指向它们,而不创建另一个 class 的某些对象。
我对这个例子及其完成的事情完全感兴趣,也许有人可以给我一些见解,看看我是否在远程使用这个接近它应该的样子?
委托是类型。引用函数而不是其他值的类型。
委托将函数作为参数传递给另一个函数。或者用作通用 class 的类型 - 实际上主要是集合。有 many 必须发明的裸指针替代品之一,因此 .NET 可以使您不必处理裸指针。
然而,他们也是这样一个案例,其中置换结果 更好 相当可观。例如,用 Dictionary<caseLabel, delegateThatTakesAArgument>
替换 switch/case 是很有可能的。如果我在 Native C++ 中给你一个 int
指针。您无法判断这是我通过引用提交的单个变量、数组的开头还是 returns int 的函数。有了所有这些指针替换,你知道。
对于这种特定情况,这些功能本身就有些矫枉过正了。代表们更是大材小用。 "PerformCalculation" 函数听起来应该是控制台应用程序的用户输入解释部分,而不是函数。
然而,没有很多好的、明确的 示例供 Delegate 使用。因此,为了学习,它可能会正常工作。通常情况下,您必须在具有硬编码操作的 switch/case 和委托之间进行判断调用。
然而,事件是我能想到的代表的罕见明确案例之一。如果你为了其他目的而学习它们,那么为了活动而学习它们。
我创建了一个 Repl,演示了使用基本委托的 Worker 模式(Action
s,一种内置于标准库中的委托类型,不接受任何参数,returns 什么也没有)。
你可以看看here。
ETA:代表最常见的用例是 asynchronous/threaded 编程。
线程需要委托给 运行,因为它们事先不知道代码是 运行,它们只是将它作为参数携带到新创建的执行线程中,否则是不可能的创建线程(好吧,没有比 C# 提供的更低级别的访问权限)
上的 MSDN 文档
同样,在异步编程中,您通常需要一个回调(在 C# 中是一个委托)来推迟代码的执行,直到满足预先存在的条件。 (例如 运行 循环,一种常见的线程替代方法,它使用单个线程逐步执行多个任务 "concurrently")
您可以在示例中使用 delegate
s 的一种方法是从选择到 CalculatorDelegate
进行映射,然后您只需查找所需的计算并执行它:
static List<CalculatorDelegate> ChoiceMap = new List<CalculatorDelegate> { Calculator.Add, Calculator.Subtract, Calculator.Multiply };
public class Calculation {
public int PerformCalculation(int choice, int number1, int number2) =>
ChoiceMap[choice-1](number1, number2);
}
但是由于委托是从 lambda 自动转换的(CalculatorDelegate
本质上是 Func<int,int,int>
),您不再需要 Calculator
class:
static List<CalculatorDelegate> ChoiceMap = new List<CalculatorDelegate> {
(n1, n2) => n1+n2,
(n1, n2) => n1-n2,
(n1, n2) => n1*n2
};
请注意,每个 lambda 中 n1
和 n2
的类型是从 CalculatorDelegate
推断出来的。现在向 PerformCalculation
添加新的操作只是向 ChoiceMap
.
添加一个新的 lambda 的问题
希望您能看到如何为 ChoiceMap
使用更复杂的类型,例如 Dictionary<string,Func<int,int,int>>
,其中每个键都是表示运算符的字符串(例如 "+"
)和该值是要执行的操作,这使得映射到简单的计算器变得容易。
我在命令行开关管理助手中使用了类似的 Dictionary
,其中每个条目都有命令名称、参数数量、要调用的委托(方法)(简单时可能是 lambda足够),命令分组和一些帮助文本,其中帮助输出是从相同的 Dictionary
.
自动生成的
我正在使用 C# 中的委托做一个简单的练习。基本前提是它只是简单地执行加法和减法等计算。
public class Calculator
{
public static int Add(int num1, int num2)
{
return num1 + num2;
}
public static int Multiply(int num1, int num2)
{
return num1 * num2;
}
public static int Subtract(int num1, int num2)
{
return num1 - num2;
}
}
并且我创建了一个委托,它将在另一个 class 中调用这些函数。
public delegate int CalculatorDelegate(int num1, int num2);
实现 class 如下所示:
public class Calculation
{
public int PerformCalculation(int choice, int number1, int number2)
{
CalculatorDelegate cd;
if (choice == 1)
{
cd = Calculator.Add;
return cd(number1, number2);
}
else if (choice == 2)
{
cd = Calculator.Subtract;
return cd(number1, number2);
}
else if (choice == 3)
{
cd = Calculator.Multiply;
return cd(number1, number2);
}
else
{
cd = Calculator.Add;
return cd(number1, number2);
}
}
}
让我对委托感到困惑的是为什么不直接执行以下操作?
if (choice == 1)
{
return Calculator.Add(number1,number2);
}
我认为我的困惑是围绕着这样一个事实:如果这些方法已经是静态的,那么即使对它们进行委托又有什么意义呢。我可以简单地将它们称为静态方法。如果我尝试使这些方法成为非静态方法,那么我不能让我的委托在另一个 class 中指向它们,而不创建另一个 class 的某些对象。
我对这个例子及其完成的事情完全感兴趣,也许有人可以给我一些见解,看看我是否在远程使用这个接近它应该的样子?
委托是类型。引用函数而不是其他值的类型。
委托将函数作为参数传递给另一个函数。或者用作通用 class 的类型 - 实际上主要是集合。有 many 必须发明的裸指针替代品之一,因此 .NET 可以使您不必处理裸指针。
然而,他们也是这样一个案例,其中置换结果 更好 相当可观。例如,用 Dictionary<caseLabel, delegateThatTakesAArgument>
替换 switch/case 是很有可能的。如果我在 Native C++ 中给你一个 int
指针。您无法判断这是我通过引用提交的单个变量、数组的开头还是 returns int 的函数。有了所有这些指针替换,你知道。
对于这种特定情况,这些功能本身就有些矫枉过正了。代表们更是大材小用。 "PerformCalculation" 函数听起来应该是控制台应用程序的用户输入解释部分,而不是函数。
然而,没有很多好的、明确的 示例供 Delegate 使用。因此,为了学习,它可能会正常工作。通常情况下,您必须在具有硬编码操作的 switch/case 和委托之间进行判断调用。
然而,事件是我能想到的代表的罕见明确案例之一。如果你为了其他目的而学习它们,那么为了活动而学习它们。
我创建了一个 Repl,演示了使用基本委托的 Worker 模式(Action
s,一种内置于标准库中的委托类型,不接受任何参数,returns 什么也没有)。
你可以看看here。
ETA:代表最常见的用例是 asynchronous/threaded 编程。
线程需要委托给 运行,因为它们事先不知道代码是 运行,它们只是将它作为参数携带到新创建的执行线程中,否则是不可能的创建线程(好吧,没有比 C# 提供的更低级别的访问权限)
上的 MSDN 文档同样,在异步编程中,您通常需要一个回调(在 C# 中是一个委托)来推迟代码的执行,直到满足预先存在的条件。 (例如 运行 循环,一种常见的线程替代方法,它使用单个线程逐步执行多个任务 "concurrently")
您可以在示例中使用 delegate
s 的一种方法是从选择到 CalculatorDelegate
进行映射,然后您只需查找所需的计算并执行它:
static List<CalculatorDelegate> ChoiceMap = new List<CalculatorDelegate> { Calculator.Add, Calculator.Subtract, Calculator.Multiply };
public class Calculation {
public int PerformCalculation(int choice, int number1, int number2) =>
ChoiceMap[choice-1](number1, number2);
}
但是由于委托是从 lambda 自动转换的(CalculatorDelegate
本质上是 Func<int,int,int>
),您不再需要 Calculator
class:
static List<CalculatorDelegate> ChoiceMap = new List<CalculatorDelegate> {
(n1, n2) => n1+n2,
(n1, n2) => n1-n2,
(n1, n2) => n1*n2
};
请注意,每个 lambda 中 n1
和 n2
的类型是从 CalculatorDelegate
推断出来的。现在向 PerformCalculation
添加新的操作只是向 ChoiceMap
.
希望您能看到如何为 ChoiceMap
使用更复杂的类型,例如 Dictionary<string,Func<int,int,int>>
,其中每个键都是表示运算符的字符串(例如 "+"
)和该值是要执行的操作,这使得映射到简单的计算器变得容易。
我在命令行开关管理助手中使用了类似的 Dictionary
,其中每个条目都有命令名称、参数数量、要调用的委托(方法)(简单时可能是 lambda足够),命令分组和一些帮助文本,其中帮助输出是从相同的 Dictionary
.