c# - 为什么允许我在非静态构造函数内为静态只读字段对象定义 SendCompletedEventHandler?

标签 c# .net-core constructor static smtpclient

private static readonly SmtpClient SmtpClient = new SmtpClient (...)


public Constructor()
{
   SmtpClient.SendCompleted += new SendCompletedEventHandler(SendCompletedMethod);
   // Above is allowed and legal. Why, when the field is marked as static read-only?
}

有什么想法为什么允许这样做吗?我真的很困惑。此外,如果构造函数被执行两次,这将产生错误。

最佳答案

字段是只读的,这意味着您无法更改字段 - 但自 SmtpClient是引用类型,字段只是引用。因此:您无法更改引用 - 但是,您可以对引用后面的对象执行任何您想要的操作(如果该类型)是可变的,这显然是可变的。这与:

class Foo
{
    public string Bar {get;set;}
}
static readonly Foo s_foo = new Foo();
//... later
s_foo.Bar = "we changed it";

将字段标记为 readonly不会使编译器将基础类型视为不可变(除非我们谈论的是具有不同规则的值类型)。它不能,因为任何方法(包括属性 getter ,它们只是具有特定形状的方法)都可以在调用者不知情的情况下更改内部状态。


请注意,对于值类型,存在 readonly struct 的概念;在那种场景中,我们保证方法不会改变内部状态,这使得编译器和运行时能够更好地决定如何应用 readonly在值类型的字段上(因此字段内容);没有readonly struct ,编译器在每次方法调用之前都会制作值类型的防御性副本,以防止字段更改;与 readonly struct ,它不会,因为它相信类型不会改变。然而,这不是,我说的是“切换到值类型”;值类型用于非常具体的目的,在不了解所有影响的情况下不应随意使用它们。

关于c# - 为什么允许我在非静态构造函数内为静态只读字段对象定义 SendCompletedEventHandler?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60448839/

相关文章:

c# - 如何让 Nuget 2.x 运行解决方案级包 Init.ps1?

c# - 如何首先在 EF6 代码中设置一个唯一的属性

c# - 由于 commandTimeout 不够健壮,如何使用 Dapper 在 C# 中获得可靠的阻塞/缓慢数据库操作超时?

c++ - 在构造函数 C++ 标准中修改 const 吗?

grails - 用大量变量更新域类对象的最佳方法是什么

c# - 以最简单的方式实例化一个对象数组?

c# - 贫血领域模型和领域服务

c# - 如何在 VSCode 中设置默认发布操作

c# - 在 .NET Core 控制台应用程序 C# 中播放音频

c# - 使用 Distinct 和 Order By 时 Entity Framework 中的多个查询和性能不佳