为何RequiresUnreferencedCodeAttribute使JsonSerializer.Deserialize重载不可用?
解决.NET6类库中调用带[RequiresUnreferencedCode]的JsonSerializer.Deserialize重载问题
问题原因
你遇到的并非编译器“找不到方法”,而是代码修剪兼容性的编译拦截。.NET6及后续版本的类库项目默认启用了可修剪性分析——即便你没主动开启代码修剪,编译器也会检查代码是否符合修剪安全标准。那个接受Utf8JsonReader和JsonSerializerOptions的Deserialize重载因内部依赖反射,被标记了[RequiresUnreferencedCode]特性,所以编译器会阻止你调用它,除非你明确声明代码不支持修剪。
解决方案
方案1:禁用可修剪性分析
如果你的类库不需要支持代码修剪,直接在项目文件(.csproj)中添加以下配置关闭修剪分析:
<PropertyGroup> <EnableTrimAnalyzer>false</EnableTrimAnalyzer> </PropertyGroup>
配置生效后,编译器将不再检查修剪兼容性,你可正常调用目标重载。
方案2:声明类不支持修剪(NuGet包推荐)
作为NuGet包,建议明确告知使用者你的代码不兼容修剪。需在整个转换器类上添加[RequiresUnreferencedCode]特性(仅标记单个Read方法无效,因为框架会调用转换器实例的方法,需标记整个类型):
using System.Diagnostics.CodeAnalysis; [RequiresUnreferencedCode("该JSON转换器依赖的反序列化方法使用反射,不支持代码修剪。")] internal class MyJsonConverter : JsonConverter<ISomeInterface> { public override void Write( Utf8JsonWriter writer, ISomeInterface value, JsonSerializerOptions options) { JsonSerializer.Serialize( writer, value.ToSerializableConfig(), options); } public override ISomeInterface? Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var deserializedObj = JsonSerializer.Deserialize<SerializableClass>( reader, options); ISomeInterface? converted = null; var successfulConversion = ConcreteTypeA.TryFromSerializable(deserializedObj, out converted) || ConcreteTypeB.TryFromSerializable(deserializedObj, out converted) || ConcreteTypeC.TryFromSerializable(deserializedObj, out converted); return converted; } }
添加特性后,编译器会允许你调用目标重载;同时当使用者的项目开启修剪时,会收到明确警告,知晓你的包不兼容修剪。
方案3:兼容修剪的替代实现(复杂但安全)
若必须支持修剪,不能依赖该重载,需手动解析Utf8JsonReader内容构造SerializableClass对象,规避反射。示例如下:
public override ISomeInterface? Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(); } var serializableObj = new SerializableClass(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) { break; } if (reader.TokenType == JsonTokenType.PropertyName) { var propName = reader.GetString(); reader.Read(); switch (propName) { case nameof(SerializableClass.Property1): serializableObj.Property1 = reader.GetInt32(); break; case nameof(SerializableClass.Property2): serializableObj.Property2 = reader.GetString(); break; // 依次处理其他属性 } } } // 后续转换逻辑保持不变 ISomeInterface? converted = null; var successfulConversion = ConcreteTypeA.TryFromSerializable(serializableObj, out converted) || ConcreteTypeB.TryFromSerializable(serializableObj, out converted) || ConcreteTypeC.TryFromSerializable(serializableObj, out converted); return converted; }
这种方式完全不依赖反射,兼容代码修剪,但需手动编写所有属性的解析逻辑,适合对修剪兼容性有严格要求的场景。
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

