如何使方法链在 C 中流畅? [英] How can I make method chaining fluent in C?

查看:31
本文介绍了如何使方法链在 C 中流畅?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现有的 C API 如下所示:

There is an existing C API that looks like this:

//data
typedef struct {int properties;} Widget;

//interface
Widget* SetWidth(Widget *const w, int width){
    // ...
    return w;
}
Widget* SetHeight(Widget *const w, int height){
    // ...
    return w;
}
Widget* SetTitle(Widget *const w, char* title){
    // ...
    return w;
}
Widget* SetPosition(Widget *const w, int x, int y){
    // ...
    return w;
}

第一个参数总是指向实例的指针,转换实例的函数总是将它作为指针返回.

The first parameter is always a pointer to the instance, and the functions that transform the instance always return it as a pointer.

我认为这样做是为了支持某种方法链?

I assume this was done to support some kind of Method Chaining?

当函数作为对象范围内的方法存在时,方法链在语言中是有意义的.鉴于 API 处于当前状态,我只能这样使用它:

Method Chaining makes sense in languages when the functions exist as methods inside the scope of the object. Given the API in its current state, I'm left using it like this:

int main(void) {
    Widget w;
    SetPosition(SetTitle(SetHeight(SetWidth(&w,400),600),"title"),0,0);
}

我可以在 C 中使用任何技术来获得与其他语言相同的流动性吗?

Are there any techniques I can use in C to get the same fluidity as in other languages?

推荐答案

C 中没有语法技巧来实现方法链,这可能在其他一些语言中使用.在 C 中,您将编写单独的函数调用,将对象指针传递给每个函数:

There is no syntax trick in C to achieve method chaining as may be used in some other languages. In C, you would write separate function calls, passing the object pointer to each function:

Widget *w = getWidget();
widgetSetWidth(w, 640);
widgetSetHeight(w, 480);
widgetSetTitle(w, "Sample widget");
widgetSetPosition(w, 0, 0);

同样可以用 C++ 和其他 OOP 语言中的方法调用来完成:

The same can be done with method calls in C++ and other OOP languages:

Widget *w = getWidget();
w->SetWidth(640);
w->SetHeight(480);
w->SetTitle("Sample widget");
w->SetPosition(0, 0);

使用上述 API,并假设每个方法返回 this 对象,方法链语法如下所示:

With the above APIs, and assuming each method returns the this object, the method chaining syntax looks like this:

getWidget()->SetWidth(640)->SetHeight(480)->SetTitle("Sample widget")->SetPosition(0, 0);

这是否比单独的语句更具可读性取决于品味和本地编码约定.我个人觉得它很麻烦而且更难阅读.在代码生成方面有一个小优势:下次调用不需要从局部变量重新加载对象指针.这种微小的优化很难证明链接语法是合理的.

Whether this is more readable than the separate statements is a matter of taste and local coding conventions. I personally find it cumbersome and harder to read. There is a small advantage in terms of code generation: the object pointer does not need to be reloaded from a local variable for the next call. This minuscule optimisation hardly justifies the chaining syntax.

一些程序员试图通过这种方式让它更可口:

Some programmers try and make it more palatable this way:

getWidget()
 -> SetWidth(640)
 -> SetHeight(480)
 -> SetTitle("Sample widget")
 -> SetPosition(0, 0);

再次,品味和编码约定的问题......但 C 等价物肯定看起来很尴尬:

Again, a matter of taste and coding conventions... But the C equivalent definitely looks awkward:

Widget *w = widgetSetPosition(widgetSetTitle(widgetSetHeight(widgetSetWidth(getWidget(), 640), 480), "Sample widget"), 0, 0);

并且没有简单的方法可以将这条链重新组织成更具可读性的内容.

And there is no easy way to reorganise this chain into some more readable.

请注意,一些最古老的 C 库函数也可以链接:

Note that some of the most ancien C library functions can be chained too:

const char *hello = "Hello";
const char *world = "World";
char buf[200];
strcpy(buf, hello);
strcat(buf, " ");
strcat(buf, world);
strcat(buf, "\n");

可以重组为:

strcat(strcat(strcat(strcpy(buf, hello), " "), world), "\n");

但更安全且更受欢迎的方法是:

But a safer and much preferred approach is this:

snprintf(buf, sizeof buf, "%s %s\n", hello, world);

有关更多信息,您可能需要阅读以下内容:

For more information, you might want to read this:

Marco Pivetta (Ocramius):流畅的界面是邪恶的

还要注意,如果 C 对象具有用于这些调用的函数指针成员,则可以使用上述所有语法,但对象指针仍必须作为参数传递.函数指针通常分组在一个结构中,指针存储在对象中,模仿C++虚方法的实现,使语法稍重:

Note also that if the C object has function pointer members for these calls, all of the above syntaxes could be used, but the object pointer must still be passed as an argument. The function pointers are usually grouped in a structure to which a pointer is stored in the object, mimicking the implementation of C++ virtual methods, making the syntax slightly heavier:

Widget *w = getWidget();
w->m->SetWidth(w, 640);
w->m->SetHeight(w, 480);
w->m->SetTitle(w, "Sample widget");
w->m->SetPosition(w, 0, 0);

链接这些也是可能的,但没有真正的收益.

Chaining these is possible too, but for no real gain.

最后,应该注意方法链不允许显式错误传播.在链接是惯用的 OOP 语言中,可以抛出异常以或多或少可口的方式发出错误信号.在 C 中,处理错误的惯用方法是返回错误状态,这与返回指向对象的指针相冲突.

Finally, it should be noted that method chaining does not allow for explicit error propagation. In OOP languages where chaining is idiomatic, exceptions can be thrown to signal errors in a more or less palatable way. In C the idiomatic way to handle errors is to return an error status, which conflicts with returning a pointer to the object.

因此,除非保证方法成功,否则建议不要使用方法链并执行迭代测试:

As a consequence, unless the methods are guaranteed to succeed, it is advisable to not use method chaining and perform iterative tests instead:

Widget *w = getWidget();
if (SetWidth(w, 640)
||  SetHeight(w, 480)
||  SetTitle(w, "Sample widget")
||  SetPosition(w, 0, 0)) {
    /* there was an error, handle it gracefully */
}

这篇关于如何使方法链在 C 中流畅?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆