Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 切换替代/可扩展编程良好实践?_C#_Linq_Switch Statement_Extension Methods_Mef - Fatal编程技术网

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

C# 切换替代/可扩展编程良好实践?,c#,linq,switch-statement,extension-methods,mef,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

首先,我的问题的一点背景;我正在用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;
}
正如您所猜测的,这不是非常可扩展的,并且很难通过添加功能来管理。我的问题是,什么是更实际的方法?

我想到了一个
列表
,为函数指定一个自定义属性,然后在启动时使用反射构建该列表。但我觉得管理起来可能仍然很麻烦,而且每次启动时可能都不需要处理能力

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

[[编辑]]
我刚刚注意到在
MEF
中使用了
ExportMetadataAttribute
。我将用我的代码对此进行演示。

我将创建一个接口,让我们调用它

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
的类型)初始化这些类的对象,而无需硬编码
开关
,只需在有新命令时创建新的
ICommandManager
实现即可

或者更奇特一点的方式,不使用Ninject的属性:

public class LoginCommandManager : ICommandManager
{
    public ReturnPacket DoYourStuff()
    {
        var ret = new ReturnPacket();
        /* Do some stuff */
        return ret;
    }
}
现在您可以使用Ninject来解决问题。使用此代码注册绑定

kernel.Bind<ICommandManager>()
    .To<LoginCommandManager>()
    .WithMetadata("Command", Command.Login);
/* ... */
kernel.Bind()
.至()
.WithMetadata(“Command”,Command.Login);
/* ... */
稍后,您可以通过以下方式解决此问题:

kernel.Get<ICommandManager>(metadata => 
    packet.Command == metadata.Get<Command>("Command"));
kernel.Get(元数据=>
packet.Command==metadata.Get(“Command”);

这篇文章似乎与linq不太相关,但linq绝对是作为一名C#程序员应该拥有的工具。将
swtich
重构为更具可扩展性的代码是一个非常常见的问题-搜索它(即如此-)以查看更多的替代方案。继承和命令到操作映射字典是常见的选项。