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

SignalR发送List<object>时调用ToString而非JSON序列化问题排查

问题根源

你遇到的核心问题是:Convert.ChangeType返回的是object类型,因此animalsAsType的实际类型为List<object>。SignalR的默认序列化器在处理object类型的集合元素时,无法识别其具体子类(Dog/Cat)的类型信息,会直接调用ToString()方法输出,而非序列化对象的属性。

解决方案

方案一:通过泛型+反射保留强类型信息

既然SendChanges的签名无法修改,我们可以用私有泛型方法完成类型转换,再通过反射调用该泛型方法,得到强类型的列表(List<T>而非List<object>),让SignalR能正确序列化属性。

代码示例:

public abstract class Animal {}
public class Dog : Animal {
    public bool GoodBoy { get; set; }
    public override string ToString() {
        return "hello from dog";
    }
}
public class Cat : Animal {
    public bool Hungry { get; set; }
}

public class MyHub : Hub {
    // 私有泛型转换方法:类型不匹配时会抛出InvalidCastException
    private List<T> CastAnimals<T>(List<Animal> animals) where T : Animal
    {
        return animals.Cast<T>().ToList();
    }

    public void SendChanges(Type type, List<Animal> animals) {
        // 反射调用泛型转换方法
        var castMethod = typeof(MyHub).GetMethod(nameof(CastAnimals), BindingFlags.NonPublic | BindingFlags.Instance)!;
        var genericCastMethod = castMethod.MakeGenericMethod(type);
        var typedAnimals = genericCastMethod.Invoke(this, new object[] { animals })!;

        // 发送强类型列表,SignalR会正确序列化属性
        Clients.Others.SendAsync($"On{type.Name}Changed", typedAnimals);
    }
}

方案二:配置SignalR序列化器开启多态支持

如果不想用反射,可以直接配置SignalR的JSON序列化选项,添加Animal的子类类型信息,让序列化器能识别多态类型,这样直接发送List<Animal>也能得到正确结果。

在Program.cs(或Startup.cs)中配置:

builder.Services.AddSignalR()
    .AddJsonProtocol(options =>
    {
        options.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, 
            new DefaultJsonTypeInfoResolver
            {
                Modifiers = {
                    typeInfo =>
                    {
                        if (typeInfo.Type == typeof(Animal))
                        {
                            typeInfo.PolymorphismOptions = new JsonPolymorphismOptions
                            {
                                TypeDiscriminatorPropertyName = "$type", // 可选:指定类型判别字段名
                                IgnoreUnrecognizedTypeDiscriminators = true,
                                DerivedTypes =
                                {
                                    new JsonDerivedType(typeof(Dog), nameof(Dog)),
                                    new JsonDerivedType(typeof(Cat), nameof(Cat))
                                }
                            };
                        }
                    }
                }
            });
    });

配置完成后,直接发送原列表即可:

public void SendChanges(Type type, List<Animal> animals) {
    Clients.Others.SendAsync($"On{type.Name}Changed", animals);
}
补充说明
  • 你之前的Convert.ChangeType操作本身没有语法错误,但由于返回类型是object,导致SignalR无法识别具体子类,才会触发ToString()。
  • 用Cast<T>替代Convert.ChangeType的好处是:类型不匹配时会直接抛出InvalidCastException,符合你要求的“实例类型不匹配则抛出异常”的需求。

内容的提问来源于stack exchange,提问作者Sillydan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 05:15:33