c# - 切换替代/可扩展编程良好实践?

标签 c# linq switch-statement extension-methods mef

首先,介绍一下我的问题的背景;我正在用 C# 编写一个模块化服务器/客户端类型程序。我有一个线程处理系统来处理来自客户端队列的数据包,这是我正在使用的示例:

public delegate object ProcessPacket(object data);
public class QueueHandler
{
    //Awesome functions/variables
    private void Proccess()
    {
        object retPacket = client.ProcessPacket(obj);
        NetworkCommon.Sendpacket(retPacket, _clientSocket);
    }
    //Even more awesome functions.
}
//Client ProcessPacket delegate
private static object ProcessPacket(object packet)
{
    ReturnPacket ret = new ReturnPacket();
    switch (packet.Command)
    {
        case Command.Login:
            //Do login stuff
            break;
        case Command.Foo;
            //Foo stuff
            break;
        case Command.Bar;
            //Bar stuff
            break;
        default:
            ret.Responce = CommandResponce.CommandNotRecognized;
    }
    return ret;
}

正如您所猜测的,这不是很好的可扩展性,并且很难通过添加功能进行管理。我的问题是,更实用的方法是什么?

我想到了一个List<string,TProcessCommand>各种各样的,为函数分配一个自定义属性,然后使用反射在启动时构建该列表。但感觉管理起来可能仍然很麻烦,并且每次启动时可能都不需要处理能力。

我考虑过的另一个选择是使用 MEF ,但我很难理解如何在不使用我不熟悉的 Linq 的情况下识别命令之间的问题。

[[编辑]] 我刚刚注意到MEF exampleExportMetadataAttribute被使用了。我将用我的代码尝试一下。

最佳答案

我会创建一个界面,我们称之为它

public interface ICommandManager
{
    ReturnPacket DoYourStuff();
}

和这样的属性:

public class HandlesAttribute : Attribute
{
    public Command HandlesCommand { get; private set; }

    public HandlesAttribute(Command cmd)
    {
        this.HandlesCommand = cmd;
    }
}

您现在可以实现用于命令处理的类,并为它们提供必要的属性。

[Handles(Command.Login)]
public class LoginCommandManager : ICommandManager
{
    public ReturnPacket DoYourStuff()
    {
        var ret = new ReturnPacket();
        /* Do some stuff */
        return ret;
    }
}

现在您可以使用例如初始化这些类的对象反射(只需查找实现 ICommandManager 的类型),无需对 switch 进行硬编码,只需在有新的 ICommandManager 实现时创建一个新的 ICommandManager 实现即可命令。

或者更奇特的方式,使用 Ninject 没有属性:

public class LoginCommandManager : ICommandManager
{
    public ReturnPacket DoYourStuff()
    {
        var ret = new ReturnPacket();
        /* Do some stuff */
        return ret;
    }
}

现在您可以使用Ninject来解决您的问题。使用此代码注册您的绑定(bind)。

kernel.Bind<ICommandManager>()
    .To<LoginCommandManager>()
    .WithMetadata("Command", Command.Login);
/* ... */

稍后您可以通过以下方式解决此问题:

kernel.Get<ICommandManager>(metadata => 
    packet.Command == metadata.Get<Command>("Command"));

关于c# - 切换替代/可扩展编程良好实践?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16727033/

相关文章:

vb.net - LinqDataSource 抛出 System.Data.Linq.Mapping.DataAttribute is not defined 错误

c# - 使用 Linq to Entity 搜索大数据导致内存使用率高

sql - 在 MySQL 的 SELECT 查询中使用 LIKE 进行 SWITCH

c# - 开关盒 c# 内的标签动画

java - 我如何使用 math.random 但仅适用于某些值?

c# - 如何创建帮助文件

c# - 如果当前数据 GridView 中存在产品 ID,则将数量增加一 (+1)

c# - 计算二进制文件中字节模式的出现次数

C# 发布目录保持为空

c# - LINQ 设计好奇心 : Skip/Take vs. SkipWhile/TakeWhile