Cosmos自定义序列化器中object[]转泛型T的数组转换问题
解决Cosmos自定义序列化器数组反序列化类型转换错误问题
问题根源
你遇到的Unable to cast object of type System.Object[] to type OurCustomType[]错误,本质是CLR不允许直接将object[]强制转换为具体类型的数组——哪怕object[]里的所有元素都是目标类型,这两种数组在CLR中属于完全不同的类型,不存在直接的转换关系(数组协变仅支持引用类型数组向上转为object[],反向不成立)。
解决方案
修改处理数组的UpdateSchemaVersionToCurrent方法,不再返回object[],而是直接创建对应元素类型的强类型数组,这样就能直接转换为T(即目标数组类型)。
修改后的核心代码
// 替换原有的object[]返回的数组处理方法 private static object UpdateSchemaVersionToCurrent(IEnumerable<JObject> jObjects, Type elementType) { Type genericListType = typeof(List<>).MakeGenericType(elementType); var list = (IList)Activator.CreateInstance(genericListType)!; foreach (var jObject in jObjects) { list.Add(UpdateSchemaVersionToCurrent(jObject, elementType)); } // 创建对应元素类型的强类型数组,而非object[] Array resultArray = Array.CreateInstance(elementType, list.Count); list.CopyTo(resultArray, 0); return resultArray; }
为什么这样能解决问题
修改后,方法返回的是实际目标类型的数组(比如OurCustomType[]),而非object[]。此时(T)(object)resultArray的强制转换会成功,因为resultArray的类型和T(数组类型)完全匹配。
完整修改后的代码片段
public override T FromStream<T>(Stream stream) { using (stream) { if (typeof(Stream).IsAssignableFrom(typeof(T))) { return (T)(object)stream; } using (var sr = new StreamReader(stream)) { using (var jsonTextReader = new JsonTextReader(sr)) { var jsonSerializer = GetSerializer(); return Deserialise<T>(jsonSerializer.Deserialize<JToken>(jsonTextReader)); } } } } private T Deserialise<T>(JToken jToken) { switch (jToken.Type) { case JTokenType.Object: var canUpgradeObject = typeof(T).GetInterfaces().Contains(typeof(IUpgradeableCosmosItem)); return canUpgradeObject ? (T)UpdateSchemaVersionToCurrent(jToken.ToObject<JObject>(), typeof(T)) : jToken.ToObject<T>(); case JTokenType.Array: var elementType = typeof(T).GetElementType()!; var canUpgradeArray = elementType.GetInterfaces().Contains(typeof(IUpgradeableCosmosItem)); return canUpgradeArray ? (T)(object)UpdateSchemaVersionToCurrent(jToken.Values<JObject>(), elementType) : jToken.ToObject<T>(); default: throw new NotImplementedException("Unknown Type to Deserialize"); } } private static object UpdateSchemaVersionToCurrent(JObject jObject, Type t) { var obj = jObject.ToObject(t); var intObj = obj as IUpgradeableCosmosItem; while (intObj!._CurrentVersion < intObj._SchemaVersion) { var originalVersion = intObj._CurrentVersion; intObj.UpgradeSchemaAndIncrementVersion(intObj._CurrentVersion + 1, jObject); if (originalVersion == intObj._CurrentVersion) { throw new InvalidOperationException($"Schema for {t.Name} was being upgraded from {originalVersion} to {intObj._CurrentVersion + 1} and the version was not updated."); } } return obj; } // 修改后的数组处理方法 private static object UpdateSchemaVersionToCurrent(IEnumerable<JObject> jObjects, Type elementType) { Type genericListType = typeof(List<>).MakeGenericType(elementType); var list = (IList)Activator.CreateInstance(genericListType)!; foreach (var jObject in jObjects) { list.Add(UpdateSchemaVersionToCurrent(jObject, elementType)); } Array resultArray = Array.CreateInstance(elementType, list.Count); list.CopyTo(resultArray, 0); return resultArray; }
内容的提问来源于stack exchange,提问作者acandylevey
相关产品推荐
相关产品推荐

