可以优化C#中的大型switch语句吗?

可以优化C#中的大型switch语句吗?,c#,.net,optimization,C#,.net,Optimization,我正在开发websocket客户端应用程序。服务器以JSON格式发送消息,我想对其进行反序列化。JSON格式的数据中有一个字符串显示消息的类型(现在大约有50种类型,将来可能会有更多) 所以我写了一个大的switch语句,如下所示: 开关(类型){ 案例“类型1”: DoSth(反序列化函数(消息)); 打破 案例“类型2”: DoSth(反序列化函数(消息)); 打破 //... } 是否可以优化此语句 这就是模型: 公共记录事件消息,其中T:IEventExtraBody { //这将始终

我正在开发websocket客户端应用程序。服务器以JSON格式发送消息,我想对其进行反序列化。JSON格式的数据中有一个字符串显示消息的类型(现在大约有50种类型,将来可能会有更多)

所以我写了一个大的switch语句,如下所示:

开关(类型){
案例“类型1”:
DoSth(反序列化函数(消息));
打破
案例“类型2”:
DoSth(反序列化函数(消息));
打破
//...
}
是否可以优化此语句

这就是模型:

公共记录事件消息,其中T:IEventExtraBody
{
//这将始终是0
[JsonPropertyName(“s”)]
公共int事件类型{get;set;}
[JsonPropertyName(“sn”)]
公共长序列号{get;set;}
[JsonPropertyName(“d”)]
public EventMessageData数据{get;set;}
公共重写字符串ToString()
{
返回JsonSerializer.Serialize(this);
}
}
公共记录EventMessageData,其中T:IEventExtraBody
{
//其他一些属性
[JsonPropertyName(“额外”)]
public EventMessageExtra{get;set;}
}
公共记录EventMessageExtra,其中T:IEventExtraBody
{
[JsonPropertyName(“类型”)]
公共字符串类型{get;set;}//此字符串指示消息的类型
[JsonPropertyName(“正文”)]
公共T体{get;set;}
}
正文(示例):

公共记录已退出guildevent:IEventExtraBody
{
[JsonPropertyName(“用户id”)]
公共字符串用户标识{get;set;}
[JsonPropertyName(“已退出”)]
公共长期存在于{get;set;}
}
当消息到达时,我使用
JsonDocument
获取类型字符串

var typeString=JsonDocument.Parse(message.Text).RootElement.GetProperty(“d”).GetProperty(“额外”).GetProperty(“类型”).GetString() 然后,我想反序列化消息并将其发布到

反序列化json字符串并发布:

\u messageHub.Publish(JsonSerializer.Deserialize(message.Text));
因为有很多
BodyType
,而且
EventMessage(message.Text)
是非法的,所以我编写了一个大型switch语句


也许我为这种情况建立了一个非常糟糕的模型。我希望你能给我一些建议。

你可以用
hashmap
替换
开关盒。要做到这一点,您只需要将每个案例移动到单独的函数中。在这里,您可以创建一个工厂方法来帮助您填写hashmap,因为情况非常相似

public class YourHub
{
    private IMessageHub _messageHub = new MessageHub();
    private Dictionary<string, Action<string, IMessageHub>> _methods;

    public YourHub()
    {
        //fill out the hashmap for all types that you have
        //make sure this hashmap is shared between operations
        _methods = new Dictionary<string, Action<string, IMessageHub>>()
        {
            {"key1",  CreateAction<EventMessage<ExitedGuildEvent>>() }
        };
    }

    //factory method for the actions
    private Action<string, IMessageHub> CreateAction<T>()
    {
        return (json, hub) => hub.Publish(JsonSerializer.Deserialize<T>(json, null));
    }

    public void ProcessMessage(string json)
    {
        var typeString = JsonDocument
             .Parse(json)
             .RootElement.GetProperty("d")
             .GetProperty("extra")
             .GetProperty("type")
             .GetString();
                    
        if (!_methods.ContainsKey(typeString)) throw new NotSupportedException();            
        var method = _methods[typeString]; 

        method(json, _messageHub);
    }      
}
公共类YourHub
{
私有IMessageHub_messageHub=新messageHub();
私有字典(private Dictionary)方法;;
公共YourHub()
{
//填写所有类型的hashmap
//确保此哈希映射在操作之间共享
_方法=新字典()
{
{“key1”,CreateAction()}
};
}
//操作的工厂方法
私有操作CreateAction()
{
return(json,hub)=>hub.Publish(JsonSerializer.Deserialize(json,null));
}
public void ProcessMessage(字符串json)
{
var typeString=JsonDocument
.Parse(json)
.RootElement.GetProperty(“d”)
.GetProperty(“额外”)
.GetProperty(“类型”)
.GetString();
if(!\u methods.ContainsKey(typeString))抛出新的NotSupportedException();
var方法=_方法[typeString];
方法(json,_messageHub);
}      
}

这款aproach不会在50个元素上给你带来巨大的性能提升,但它看起来更干净。运行时的复杂性是
O(1)
O(n)
switch case
相比,但是它需要
O(n)
额外的空间。

一个比大开关更好的解决方案可能是将反序列化函数重构为接口和类

按类型注册它,然后解析它。可以使用DI容器,也可以使用映射到的字典

interface IMessageDeserializer {

    object Deserialize(Message message);

}

class Type1Deserializer : IMessageDeserializer {

    public object Deserialize(Message message){
      // Implementation that returns a Type1
      return new Type1(){

      };
    }

}


// Register your serializers (you can use also a DI container  but this is simpler just to show how) in a dictionary, preferably reused

Dictionary<Type, IMessageDeserializer> serializers = new Dictionary<Type, IMessageDeserializer>();

serializers.Add("type1", new Type1Deserializer());
serializers.Add("type2", new Type2Deserializer());
serializers.Add("type3", new Type3Deserializer());

// When you need it, use it like this:

string type = "type1"; // This is from your other code
var message = GetMessage(); // This is from your other code

IMessageDeserializer serializer = serializers[type];    
object deserializedMessage = serializer.Deserialize(message);

// To create your event message, either add a constraint to the T of IMessageDeserializer so you can pass it into another function that creates the event message or just simply return the messagehub message as json directly from your IMessageDeserializer implementation)
接口IMessageDeserializer{
对象反序列化(消息);
}
类Type1Deserializer:IMessageDeserializer{
公共对象反序列化(消息){
//返回类型1的实现
返回新的Type1(){
};
}
}
//在字典中注册您的序列化程序(您也可以使用DI容器,但这更简单,只是为了说明如何使用),最好是重用
字典序列化器=新字典();
添加(“type1”,新的Type1Deserializer());
添加(“type2”,新的Type2Deserializer());
添加(“type3”,新的Type3Deserializer());
//需要时,请按如下方式使用:
字符串类型=“类型1”;//这是您的其他代码
var message=GetMessage();//这是您的其他代码
IMessageDeserializer序列化程序=序列化程序[类型];
object deserializedMessage=序列化程序。反序列化(消息);
//要创建事件消息,可以向IMessageDeserializer的T添加一个约束,以便将其传递到创建事件消息的另一个函数中,也可以直接从IMessageDeserializer实现以json形式返回messagehub消息)

(我是从内存中写的,因此我对所有错误表示歉意)

需要更多信息,因为它没有最少的代码来可视化问题。这种设计的问题是,您无法获得类型化实例。或
动态
?您知道signar是基于WebSockets的,它像魔术一样为您完成所有这些工作。如果您使用分层开关语句,您将达到Log(n)时间复杂度,而不是O(n)