扩展方法和成员方法:为什么编译器(内部)对每个方法的实现不同?

发布于 2024-12-02 13:58:05 字数 754 浏览 4 评论 0原文

考虑一下这段代码:

 A a = null;
 a.f(); //Will it throw NullReferenceException?

上面的代码会抛出 NullReferenceException 吗?

答案是:这取决于 f() 是什么。

这种差异引出了一个问题:C# 编译器如何实现和查看每种类型的方法?另外,为什么成员方法必须抛出异常即使它不访问任何成员数据?看来C#编译器提前假设成员方法将访问成员数据,因此如果对象为null,它会抛出异常,因为使用null对象无法访问成员数据。但是,在扩展方法的情况下,它会推迟此决定,直到它实际上尝试使用空引用访问成员数据,

我的理解在多大程度上是正确的?如果是这样,为什么会有这种差异?

是的,我知道如果f()是一个扩展方法,那么af()就相当于写AExt.f(a),所以后者不应该抛出异常,直到使用 a 访问成员。但我的重点主要是编译器实现(它甚至可以以相同的方式实现成员方法)。

Consider this code:

 A a = null;
 a.f(); //Will it throw NullReferenceException?

Will the above throw NullReferenceException?

The answer is : it depends on what f() is.

This difference leads to a question: how each type of method is implemeneted and viewed by C# compilers? Also, why member method must throw exception even if it doesn't access any member data? It seems that C# compiler makes an assumption in advance that member method will access member data, and so it throws exception if the object is null, as using null object member data cannot be accessed. However, in case of extension method, it postpones this decision till it actually attempts to access member data using null reference, only then it throws exception.

How far my understanding is correct? And if that is so, why this difference?

Yes, I know that if f() is an extension method, then a.f() is equivalent to writing AExt.f(a), so the latter shouldn't throw exception until a is used to access member. But my focus is mostly on the compiler implementations (which can implement even member methods in the same way).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

请叫√我孤独 2024-12-09 13:58:05

是的,这就是这段代码的行为方式(如果扩展方法不检查 null 并自行引发异常)。您是对的,如果该方法不访问该类的任何实例字段(直接或间接),则在 null 上调用非虚拟实例方法可以工作。

但是语言设计人员认为这会令人困惑,因此他们通过使用 callvirt IL 指令来确保该对象不为 null

使用扩展方法,这并不那么令人困惑(没有人期望 thisnull,但声明的参数 this IEnumerablesource 应该是检查)。并且您可以像普通静态方法一样调用扩展方法,因此无论如何它都应该检查 null 。此外,调用该函数的两种方式的行为可能应该完全相同。

Yes, this is how this code behaves (if the extension method doesn't check for null and throws an exception by itself). You're right that calling non-virtual instance method on null could work, if that method doesn't access any instance fields of the class (directly or indirectly).

But the language designers felt this would be confusing, so they make sure that the object is not null by using the callvirt IL instruction.

With extension methods, this is not as confusing (nobody expects this to be null, but an argument declared this IEnumerable<TSource> source should be checked). And you can call extension method as normal static method, so it should check for null anyway. Also, both ways of calling the function should probably behave exactly the same.

肩上的翅膀 2024-12-09 13:58:05

当对象为 null 时,实例方法必须抛出 NullReferenceException,因为它们本质上保证在执行该方法时该对象可用。将实例方法视为对象实例执行的操作,当对象本身不存在时,甚至无法调用该操作。扩展方法只是语法糖,编译器会立即将它们转换为您上面提到的 AExt.f(a)。这只是一种便利,并且可以作为一种视觉效果来帮助更好地阅读代码。

对于无论实例是否可用都希望调用方法的情况,该语言提供静态方法作为功能。正如您所知,扩展方法是静态方法。

The instance methods must throw the NullReferenceException when the object is null, because they inherently guarantee that the object is available when that method is executed. Think of the instance methods as an action that the object instance performs and when the object itself is not existent, then the action could not even be invoked. The extension methods are just syntactic sugar and the compiler immediately translates them as you mentioned above AExt.f(a). This is just a convenience and serves as an eye candy to help read the code better.

For the cases where you would want to call a method regardless of whether the instance is available or not, the language provides static methods as the feature. As you can tell, the extension methods are static methods.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文