c# - 动态回调方法
问题描述
我有一种情况,我循环项目并根据一些计算分配一个“回调”方法,在循环结束时调用这个方法(基于优先级和计算“获胜”的方法)。
在像 JS 这样的动态类型语言中非常容易,但是因为我是类型语言的新手,所以我需要一些关于动态回调方法的帮助。
请阅读评论:
bool MethodA(MyClass item, List<MyClass> items) {
int priority = 0;
// here should be local variable for method,
// for example in JS it would be "var func;"
for (int i = 0; i < items.Count; i++) {
if (priority <= 4) {
float expensiveValue;
if (MethodB(item, items[i], out expensiveValue)) {
priority = 4;
// assing a callback "func" that use "expensiveValue"
// so that I don't have to calculate it again, e.g in JS:
/* func = function () {
// use "expensiveValue", it's bound to this context
return true;
}; */
}
}
if (priority <= 3) {
float expensiveValue = MethodC(item, items);
if (expensiveValue > 5f) {
priority = 3;
// same as in "if (priority <= 4)"
}
}
// and other priority if's
}
// now that for loop is done, one of these callbacks
// was assigned to "func", in JS I'd call "return func();"
}
编辑:回调方法的几个例子
bool
总是返回,但参数不同。
bool Method1(MyClass items[i], Vector3 expensiveValue);
bool Method2(MyClass items[i], float expensiveValue);
解决方案
感谢有趣的问题。当前的答案很棒,并提供了一种方法来完成您对 C# 的要求。我会建议一种替代方法,使代码更容易测试,对我来说,更清楚一点。您在 javascript 中所做的事情的关键是捕获局部范围的变量,这很酷,但也使这种类型的代码难以测试并且有点混乱。经常做的一件事是将这些变量提升到他们自己的类中。您可以对选择代码执行相同操作。例如:
class PriorityMethod
{
public virtual bool Invoke()
{
return false;
}
}
class MethodPriorityB : PriorityMethod
{
public MyClass FirstItem { get; set; }
public MyClass SecondItem { get; set; }
public float ExpensiveValue { get; set; }
public override bool Invoke()
{
// use the properties to derive your result...
return true;
}
}
这两个-从您的示例中显然不仅仅是一个子类-代表我们最终要调用的方法及其作用域变量。我们可以这样提取选择逻辑:
class PriorityMethodSelector
{
public PriorityMethod Create(ref int priority, MyClass first, MyClass second)
{
if (priority <= 4)
{
// do something to drive the expensive value
return new MethodPriorityB() { FirstItem = first, SecondItem = second, ExpensiveValue = 1 };
}
return null;
}
public PriorityMethod Create(ref int priorty, MyClass first, IEnumerable<MyClass> items)
{
return null;
}
}
然后我们把它们放在一起:
PriorityMethodSelector selector = new PriorityMethodSelector();
int priority = 0;
PriorityMethod method = null;
foreach(var item in items)
{
method = selector.Create(ref priority, special, item) ?? method;
method = selector.Create(ref priority, item, items) ?? method;
}
if (null != method)
method.Invoke();
我见过的用于此类问题的另一种替代方法是使用状态机。这会增加更多的复杂性,但如果您的选择逻辑变得更复杂,这将很有用。
推荐阅读
- javascript - evenlistener 中的 textContent 返回 NaN
- c - 如何设置 XDP 挂钩使用的内核/线程数?
- javascript - puppeteer waitForSelector 和“不存在”元素
- go - 不能对 r.route 进行切片(输入 *[]Route)
- c# - 缺少 UWP 的 Windows 桌面扩展 SDK
- javascript - 如何从 pub 子函数更新 Firestore 字段
- git - 同一本地 git 存储库上的多个程序员都使用 Visual Studio
- aws-glue - 'ignore.malformed.json'='true' 在 AWS Glue 表中设置,但是 Athena 仍然提供 JSON 对象 - JSONException:错误
- javascript - 在链接页面上执行 jQuery 函数
- python - 如何使 Tkinter 滚动条编辑实时