You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 08:13:21