如何在.NET 4+中实现ISerializable且不违反继承安全规则?
我来帮你拆解这个问题——这本质上是.NET 4.0开始的安全规则变更(Level2安全规则)和部分信任沙箱环境交互导致的权限匹配问题,咱们一步步解决:
问题根源
在.NET 3.5(Noda Time 1.x的目标框架)中,CLR使用Level1安全规则,对显式接口实现的安全权限检查比较宽松。但.NET 4.0+默认启用了Level2安全规则,要求实现接口方法的安全可访问性必须和原接口方法完全一致。
具体到你的场景:ISerializable.GetObjectData方法在.NET 4+中是被标记为[SecurityCritical]的,而你的结构体在.NET Fiddle这类沙箱(部分信任环境)中运行时,未正确标记的显式实现方法触发了"继承安全规则违反"的TypeLoadException。
正确的解决方案组合
要让可序列化结构体在.NET 4.5+的沙箱环境中正常工作,需要同时满足以下两个条件:
1. 为程序集添加AllowPartiallyTrustedCallers属性
这是沙箱环境运行的基础,告诉CLR该程序集允许被部分信任的代码调用,添加到你的类库项目的AssemblyInfo.cs或者命名空间上方:
[assembly: AllowPartiallyTrustedCallers]
2. 对显式实现的GetObjectData方法标记[SecurityCritical]
因为ISerializable.GetObjectData本身是SecurityCritical级别的,你的实现必须严格匹配这个安全级别。注意要把标记直接加在显式实现的方法上,即使是结构体:
[Serializable] public struct CustomStruct : ISerializable { private CustomStruct(SerializationInfo info, StreamingContext context) { } [SecurityCritical] void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { // 这里实现你的序列化逻辑 throw new NotImplementedException(); } }
为什么不推荐回退到Level1规则?
你提到的添加[assembly: SecurityRules(SecurityRuleSet.Level1)]虽然能临时解决问题,但会让程序集回到旧的安全模型,不仅可能引入潜在安全风险,还不符合.NET 4+的设计意图,所以不建议作为长期方案。
为什么之前的尝试没生效?
- 单独添加
SecurityPermission:这只是声明方法需要的权限,但没有匹配接口方法的安全级别标记,Level2规则下仍然不满足权限一致性要求。 - 单独添加
SecuritySafeCritical:这个标记用于允许部分信任代码调用关键方法,但接口方法本身是SecurityCritical,所以实现必须也是SecurityCritical,SafeCritical的级别不匹配。 - 未添加
AllowPartiallyTrustedCallers:即使标记了SecurityCritical,部分信任的沙箱代码也无法调用你的程序集,必须有这个属性放行。
验证修改
按照上述调整后,你的测试项目应该能正常运行:
- 确保UntrustedCode程序集同时添加
[assembly: AllowPartiallyTrustedCallers]和结构体GetObjectData方法的[SecurityCritical]标记 - 不需要修改CodeRunner项目的代码
- 运行后不会再抛出
TypeLoadException
内容的提问来源于stack exchange,提问作者Jon Skeet

