C# C泛型,寻求帮助了解一个示例

C# C泛型,寻求帮助了解一个示例,c#,generics,C#,Generics,我试图理解一段实现泛型的现有代码,因此它建立了一个泛型字典,然后将项添加到字典中,其中键是委托的类型和值 private readonly Dictionary<Type, Func<actionType, Task>> requestedActions; private void AddAction<T>(Func<T, Task> action) where T : actionType { this.requestedActions

我试图理解一段实现泛型的现有代码,因此它建立了一个泛型字典,然后将项添加到字典中,其中键是委托的类型和值

private readonly Dictionary<Type, Func<actionType, Task>> requestedActions;

private void AddAction<T>(Func<T, Task> action) where T : actionType
{
    this.requestedActions[typeof(T)] = (request) => action((T)request);
}

this.AddAction<AddItem>(this.HandleAdd);
this.AddAction<UpdateItem>(this.HandleUpdate);
this.AddAction<DeleteItem>(this.HandleDelete);

 private Task HandleAdd(AddItem message)
    {
         .....
    }

通用示例允许您在运行时动态添加处理程序,而switch语句基本上是烘焙到代码中的

这是我能想出的主要例子


另外,一般示例看起来很花哨。

如果不知道使用场景,很难判断哪种方法更好,但是对于最初的示例,您将能够从数据库中拉入并序列化数据,而无需在每次引入新操作时添加switch语句。看起来通过使用泛型节省了开发时间


让我们也来看看与switch语句相比,使用这个示例的速度差异是什么。如果在函数调用时已准备好类型,则字典时间检索为O1。这与switch语句减去必须处理switch语句的时间相同

当您使用泛型数据结构字典作为示例时,这个问题与多态性有关,而不是泛型

正如已经告诉您的,switch是坏的,因为如果您想添加另一个case,您必须修改这段代码。开关通常是代码气味,表示应使用多态性

在这种情况下使用开关违反了打开/关闭原则。简而言之,这个原则说,代码应该为更改而打开,但为修改而关闭。您提供的示例遵循此规则。如果您想要另一个操作,您不需要触摸此代码,只需添加另一个任务类即可。使用switch,您需要修改现有代码


我希望这有帮助

使用开关时,如果您有新案例,则必须修改代码。使用字典,您可以注册新案例,而无需修改一行代码。同样,泛型在这里是不相关的,没有泛型的原则是一样的;可扩展性和可维护性在该解决方案中,ProcessData不需要更改。想象一下你有10个这样的方法——通过在一个地方添加一个新的类型,即使可能是10倍,也能让所有的方法都适应新的类型,这通常比寻找这10个方法并为初学者更改它们更方便,如果你不能更改这些方法,因为它不是你的代码呢?源类型上的虚拟方法是实现此效果的另一种方法。switch通常是最差的方法,因为它会导致大量重复。如果在processData函数中switch case只存在一次,那么它不是向switch添加新case还是向dictionary添加新项?所以无论哪种方式都需要代码更改?重要的不是代码必须更改-重要的是代码必须更改多少以及您希望更改的位置。理想情况下,在尽可能少的地方。如果现在和将来唯一进行类型识别的地方是processData,那么是的,您选择哪种解决方案无关紧要。谢谢@Jeroenmoster,我认为在本例中,您的权利,使用哪种解决方案无关紧要!也许这只是一个偏好,我只是想确定是否有技术上的原因,我不同意泛型示例看起来确实很花哨:我只是想从技术角度理解这样一个简单示例的区别,为什么重复代码时需要使用泛型不是问题!动态添加处理程序会有更好的性能吗?一般情况下速度较慢,但允许在运行时进行更改您可以添加更多EventHandler,而开关会烘焙到代码中,速度更快,但动态更改并不容易。当您使用第三方库时,您会欣赏这种设计—您希望将自定义行为添加到现有代码中,例如处理库作者未预测到的特定情况。如果某个地方有一个用于AddAction的公共API,这意味着您可以在使用库之前,使用自定义操作调用它,从而修改功能,而无需重新编译库,这可能会让人感到麻烦,也可能是不通用的编译时材料?通常是这样,但您可以看到他正在使用字典
 public bool ProcessData(ItemMessage request)
 {
    Func<ItemMessage, Task> requestAction;
    if (this.requestedActions.TryGetValue(requestType, out requestAction))
    {
          requestAction(request).Await();
    }                   

 }
switch (actionType)
      {
          case AddItem:
              HandleAdd();
              break;
          case UpdateItem:
              HandleUpdate();
              break;
      ...
      }