草庐IT

c# - 更改了 .NET 4.5 中 string.Empty(或 System.String::Empty)的行为

coder 2023-07-09 原文

短版:

C# 代码

typeof(string).GetField("Empty").SetValue(null, "Hello world!");
Console.WriteLine(string.Empty);

编译并运行时,给出输出 "Hello world!"在 .NET 4.0 及更早版本下,但提供 ""在 .NET 4.5 和 .NET 4.5.1 下。

如何像这样忽略对字段的写入,或者谁重置该字段?

加长版:

我从来没有真正理解为什么 string.Empty字段(也称为 [mscorlib]System.String::Empty )不是 const (又名 literal),参见“Why isn't String.Empty a constant?”。这意味着,例如,在 C# 中我们不能使用 string.Empty在以下情况下:
  • switch声明形式 case string.Empty:
  • 作为可选参数的默认值,如 void M(string x = string.Empty) { }
  • 应用属性时,例如 [SomeAttribute(string.Empty)]
  • 需要编译时常量的其他情况

  • 这对众所周知的“宗教 war ”是否使用string.Empty有影响或 "" ,见“In C#, should I use string.Empty or String.Empty or "" to intitialize a string?”。

    几年前,我通过设置 Empty 自娱自乐。通过反射到其他一些字符串实例,看看 BCL 的多少部分因此开始表现异常。这是相当多的。和Empty的变化引用似乎在应用程序的整个生命周期中都存在。现在,前几天我试图重复那个小特技,但后来使用了 .NET 4.5 机器,我再也做不到了。

    (注意!如果你的机器上有 .NET 4.5,可能你的 PowerShell 仍然使用旧版本的 .NET(编辑:仅适用于 Windows 7 或更旧版本,其中 PowerShell 没有更新到 PowerShell 2.0 以上),所以尝试复制-将 [String].GetField("Empty").SetValue($null, "Hello world!") 粘贴到 PowerShell 中以查看更改此引用的一些效果。)

    当我试图寻找原因时,我偶然发现了有趣的线程“What's the cause of this FatalExecutionEngineError in .NET 4.5 beta?”。在该问题的公认答案中,是否注意到通过 4.0 版,System.String有一个静态构造函数 .cctor其中领域Empty已设置(在 C# 源代码中,当然,这可能只是一个字段初始值设定项),而在 4.5 中不存在静态构造函数。在这两个版本中,字段本身看起来是一样的:
    .field public static initonly string Empty
    

    (如 IL DASM 所见)。

    String::Empty 外没有其他字段似乎受到了影响。作为一个例子,我试验了 System.Diagnostics.Debugger::DefaultCategory .这种情况看起来很相似:一个包含 static readonly 的密封类( static initonly ) string 类型的字段.但是在这种情况下,通过反射更改值(引用)可以正常工作。

    回到问题:

    从技术上讲,Empty 怎么可能?当我设置字段时,似乎没有改变(在 4.5 中)?我已经验证 C# 编译器不会在读取时“作弊”,它输出 IL 如下:
    ldsfld     string [mscorlib]System.String::Empty
    

    所以应该阅读实际的领域。

    在对我的问题进行悬赏后编辑:请注意,写操作(肯定需要反射,因为字段是 readonly(在 IL 中又名 initonly))实际上按预期工作。它是 阅读 异常的操作。如果你用反射阅读,如 typeof(string).GetField("Empty").GetValue(null) ,一切正常(即看到值的变化)。请参阅下面的评论。

    所以更好的问题是:为什么这个新版本的框架在读取这个特定字段时会作弊?

    最佳答案

    不同之处在于新版本 .NET 的 JIT,它显然优化了对 String.Empty 的引用。通过内联对特定 String 的引用实例而不是加载存储在 Empty 中的值 field 。这在 的定义下是合理的。仅初始化约束 在 ECMA-335 Partition I §8.6.1.2 中,可以解释为 String.Empty 的值String后字段不会改变类被初始化。

    关于c# - 更改了 .NET 4.5 中 string.Empty(或 System.String::Empty)的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16618302/

    有关c# - 更改了 .NET 4.5 中 string.Empty(或 System.String::Empty)的行为的更多相关文章

    1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

      作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

    2. ruby-on-rails - Ruby on Rails 迁移,将表更改为 MyISAM - 2

      如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设

    3. ruby - 如何模拟 Net::HTTP::Post? - 2

      是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

    4. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

      我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

    5. ruby - Capistrano 3 在任务中更改 ssh_options - 2

      我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

    6. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

      我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

    7. c# - 如何在 ruby​​ 中调用 C# dll? - 2

      如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

    8. ruby - 更改 ActiveRecord 中对象的类 - 2

      假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。

    9. C# 到 Ruby sha1 base64 编码 - 2

      我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

    10. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

      对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

    随机推荐