C# 链式方法

C# 链式方法,c#,.net,C#,.net,很久以前,我看到了一些东西,它允许您动态地将一系列方法链接在一起。不记得是C,还是C++?< /P> 事情是这样的: obj.Foo() .Bar() .Moar(); 方法: Foo(); Bar(); Moar(); 然后创建一个订阅(因为没有更好的词)上述任何或所有方法(取决于程序员的规范)的对象,传入该对象的任何内容都将通过所有订阅的方法运行 我这样问是因为我正在为一个程序开发一个内核,它取决于各种选择,可能需要也可能不需要某些方法。由于这个程序需要非常严格的编码(我不希望在if

很久以前,我看到了一些东西,它允许您动态地将一系列方法链接在一起。不记得是C,还是C++?< /P> 事情是这样的:

obj.Foo()
 .Bar()
 .Moar();
方法:

Foo();
Bar();
Moar();
然后创建一个订阅(因为没有更好的词)上述任何或所有方法(取决于程序员的规范)的对象,传入该对象的任何内容都将通过所有订阅的方法运行

我这样问是因为我正在为一个程序开发一个内核,它取决于各种选择,可能需要也可能不需要某些方法。由于这个程序需要非常严格的编码(我不希望在if/else语句上浪费处理器周期……它会累加起来),我想知道是否有人记得我试图传达的内容,以及C#等价物是什么

谢谢, -R

听起来像是一个事件:

声明:

public event Action Something;
认购:

obj.Something += x.Foo;
...
obj.Something += y.Bar;
...
obj.Something += z.Moar;
然后调用:

protected virtual void OnSomething() {
    var handler = Something;
    if(handler != null) handler();
}
...
OnSomething(); // call ^^^^^^
这将调用所有3个方法,但具有松散耦合

请注意,您可以对delagate而不是事件执行完全相同的操作。还要注意,事件通常有一个更具体的
void(objectsender,SomeEventArgs args)
签名(但这是惯例,不是要求)。

听起来像是一个事件:

声明:

public event Action Something;
认购:

obj.Something += x.Foo;
...
obj.Something += y.Bar;
...
obj.Something += z.Moar;
然后调用:

protected virtual void OnSomething() {
    var handler = Something;
    if(handler != null) handler();
}
...
OnSomething(); // call ^^^^^^
这将调用所有3个方法,但具有松散耦合


请注意,您可以对delagate而不是事件执行完全相同的操作。还要注意,事件通常有一个更具体的
void(objectsender,SomeEventArgs-args)
签名(但这是惯例,不是要求)。

Marc的答案是C#中最接近的,但值得指出的是,这不会比一系列
的签名快,如果
的话,它会更慢

也许您指的是在方法末尾将
JMP
转到汇编程序中另一个地址的方法,以避免调用
和两个后续的
RET
s,这就是X86汇编程序,但是现代优化编译器将为您进行优化

例如,您使用
call
调用一个方法,该方法将返回地址推送到堆栈中,然后在另一个方法的末尾,您可以
调用另一个方法,但它完成后,执行
RET
返回到第一个方法的末尾,执行
RET
跳回原始调用方。但是,如果在第一个方法的末尾有一个
JMP
,它将链接到第二个方法,而第二个方法的
RET
将返回给调用方,从而节省额外的跳转/一些堆栈操作



根据您想要执行的操作,您可以使用框架()的反射发射部分在.NET中动态生成代码。如果您想以文本方式将方法编译到内存中,还可以使用内置的C#编译器将方法动态编译到内存中。这可能就是你所想的。

马克的答案是C#中最接近的答案,但值得指出的是,这不会比一系列的
快,如果
s,速度会慢一些

也许您指的是在方法末尾将
JMP
转到汇编程序中另一个地址的方法,以避免调用
和两个后续的
RET
s,这就是X86汇编程序,但是现代优化编译器将为您进行优化

例如,您使用
call
调用一个方法,该方法将返回地址推送到堆栈中,然后在另一个方法的末尾,您可以
调用另一个方法,但它完成后,执行
RET
返回到第一个方法的末尾,执行
RET
跳回原始调用方。但是,如果在第一个方法的末尾有一个
JMP
,它将链接到第二个方法,而第二个方法的
RET
将返回给调用方,从而节省额外的跳转/一些堆栈操作



根据您想要执行的操作,您可以使用框架()的反射发射部分在.NET中动态生成代码。如果您想以文本方式将方法编译到内存中,还可以使用内置的C#编译器将方法动态编译到内存中。这可能就是你所想的。

你能回忆起一些API中“流畅”编码风格的片段吗

每个函数都将其对象实例作为函数结果返回,因此您可以像这样将调用链接在一起:

obj.Foo()
 .Bar()
 .Moar();
这里没有特别神奇的性能提升,它只是让您不必反复键入对象实例变量名


好的,使用函数result作为下一次调用的实例参数可能会获得很小的效率。如果函数结果在寄存器EAX中返回,下一次调用的实例指针在寄存器EAX中传递,那么此流畅调用模式将保存一条或两条指令,以便将实例指针加载到EAX寄存器中,以便下一次调用。但就性能调整而言,这确实是一个很小的问题。

您能回忆一下一些API中的“流畅”编码风格的片段吗

每个函数都将其对象实例作为函数结果返回,因此您可以像这样将调用链接在一起:

obj.Foo()
 .Bar()
 .Moar();
这里没有特别神奇的性能提升,它只是让您不必反复键入对象实例变量名


好的,使用函数result作为下一次调用的实例参数可能会获得很小的效率。如果函数结果在寄存器EAX中返回,下一次调用的实例指针在寄存器EAX中传递,那么此流畅调用模式将保存一条或两条指令,以便将实例指针加载到EAX寄存器中,以便下一次调用。但是,就性能调整而言,这确实很小。

您可以使用
委托解决它

您可以使用
委托解决它

您知道每秒有数十亿个处理器周期吗?除非你愿意,否则你不会浪费它们