Blazor WASM JS Interop序列化问题:C# object属性仅返回JsonElement
问题:JS任意类型序列化为C#对象时object属性变为JsonElement的原因及解决方案
我尝试将JS中的任意类型序列化为C#中的对象,但始终无法正常工作。我的EventAction类拥有以下属性:
public DotNetObjectReference<EventAction<T>> DotNetObjRef { get; }
该属性用于从JS代码调用事件,示例如下:
function onCellValueChanged(data, handler) { var mapped = { columnName: data.column.colId, // string rowIndex: data.rowIndex, // number oldValue: data.oldValue, // any newValue: data.newValue, // any }; handler.dotNetObjRef.invokeMethodAsync('Invoke', mapped); }
调用方法本身运行正常,但序列化仅部分生效。示例中我定义了CellValueChangedArgs类:
public class CellValueChangedArgs { public string ColumnName { get; set; } = string.Empty; public int RowIndex { get; set; } public object? OldValue { get; set; } public object? NewValue { get; set; } }
当生成该类的实例时,string和int类型的属性可正常序列化,但object?类型的OldValue和NewValue并未得到实际值(如字符串、数字、日期等),而是JsonElement实例。若将这两个属性的类型改为string,则序列化可正常进行。
请问出现该问题的原因是什么?将其序列化为字符串再手动转换是否为合适的解决方案?
原因分析
- .NET默认的System.Text.Json序列化器处理
object类型属性时,无法提前推断出该属性对应的具体CLR类型,因此会将JSON值保留为JsonElement类型(这是JSON DOM的基本元素,用于存储原始JSON的结构和值)。 - 对于
string、int这类类型明确的属性,序列化器可以直接匹配JSON中的对应类型,所以能正确完成反序列化。
解决方案评估
1. 序列化为字符串再手动转换:可行但不推荐
这种方法确实能解决问题,但需要手动编写各种类型的转换逻辑,比如判断值是数字、日期还是字符串,再做对应转换。不仅代码冗余,还容易出现类型转换错误,维护成本较高,只适合临时的简单场景。
2. 更优的替代方案
- 泛型类改造:如果能提前确定
OldValue/NewValue的类型,将CellValueChangedArgs改为泛型类:
序列化器可以明确目标类型,自动完成反序列化,同时保留静态类型检查的优势。public class CellValueChangedArgs<T> { public string ColumnName { get; set; } = string.Empty; public int RowIndex { get; set; } public T? OldValue { get; set; } public T? NewValue { get; set; } } - 自定义Json转换器:编写继承自
JsonConverter<object>的转换器,根据JsonElement的ValueKind判断原始类型,转换为对应的CLR类型(如int、string、DateTime等)。示例如下:
使用时在public class ObjectJsonConverter : JsonConverter<object> { public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.TokenType switch { JsonTokenType.String => reader.GetString(), JsonTokenType.Number => reader.TryGetInt64(out long l) ? l : reader.GetDouble(), JsonTokenType.True => true, JsonTokenType.False => false, JsonTokenType.Null => null, _ => JsonDocument.ParseValue(ref reader).RootElement.Clone() }; } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, value.GetType(), options); } }JsonSerializerOptions中添加该转换器,或者给object属性标记[JsonConverter(typeof(ObjectJsonConverter))],即可自动处理任意类型的反序列化。 - 使用dynamic类型:将
OldValue/NewValue改为dynamic类型,这样在使用时可以直接调用对应类型的方法,但会失去静态类型检查,运行时可能出现类型错误,适合快速迭代的场景。
内容的提问来源于stack exchange,提问作者Goran
相关产品推荐
相关产品推荐

