在我的应用程序中,我正在处理一个包含IMyInterface个实例的列表.不是全部,但其中一些in addition也实现了IAnotherInterface.请注意,IAnotherInterface不是从IMyInterface派生出来的.遵循单一责任原则,我有一个单独的类,它通过Process方法处理IMyInterfaces个实例.现在我正在为设计 Select 而苦苦挣扎,无论是

  1. 签名应该是Process(IEnumerable<IMyInterface> items),我在此方法中筛选出IAnotherInterface
  2. 或者签名应该是Process(IEnumerable<IAnotherInterface> items),这意味着过滤必须由"客户端"在处理方法之外进行.

为了更清楚地说明这一点,我在两个代码选项之间苦苦挣扎:

// alternative 1:
List<MyInterface> items = GetItems(); // code not shown here
foreach(var item in items)
{
    // do some other processing before, not shown here

    // pass items to Process(IEnumerable<IMyInterface> items)
    myProcessor.Process(items);                
            
    // do some other processing afterwards, not shown here
}

// or alternative 2:
List<MyInterface> items = GetItems(); // code not shown here
foreach (var item in items)
{
    // do some other processing before, not shown here

    // pass items to Process(IEnumerable<IAnotherInterface> items)
    // -> need to filter first
    var filteredItems = filterForIAnotherInterface(items);
    myProcessor.Process(filteredItems);

    // do some other processing afterwards, not shown here
}

Select 一个而不是另一个,有什么好的理由吗?我自己的 idea 是,备选方案1更容易用于客户端,但Process方法必须进行过滤,这在其主要责任之外增加了某种额外的责任.另一方面,我认为备选方案2在某种程度上降低了处理流水线的可读性.

推荐答案

没有绝对的规则来指导这样的API设计决策.一方面,你可能想要尽可能地明确.

显性比隐性要好.

-The Zen of Python-The Zen of Python

另一种说法是应用Principle of Least Surprise.如果您有一个签名为void Process(IEnumerable<IMyInterface> items)的方法,客户端代码将期望这样的方法处理IMyInterface个对象.这样的客户端可能会感到惊讶,如果它传递一个IMyInterface个对象的集合,这些对象do not也实现IAnotherInterface,然后实现nothing happens.令人惊讶.

另一方面,Robustness Principle(Postel定律)可能会争辩说,如果Process可以处理IMyInterface个对象,那么它也应该接受它们.


由于我不知道OP中的更多内容,所以听起来Postel定律really在这里并不适用,因为Process方法实际上没有handle任何IMyInterface对象-它只是忽略它们.

因此,在不知道更多的情况下,听起来API应该是void Process(IEnumerable<IAnotherInterface> items).

另一方面,我认为备选方案2在某种程度上降低了处理流水线的可读性.

只要用OfType:

myProcessor.Process(items.OfType<IAnotherInterface>());

如果您真的想使管道显式,您可以通过引入(内部)扩展方法来反转参数:

public static void ProcessWith(
    this IEnumerable<IAnotherInterface> items,
    SomeProcessor processor)
{
    processor.Process(items);
}

这将使您能够像这样编写管道:

items.OfType<IAnotherInterface>().ProcessWith(myProcessor);

Csharp相关问答推荐

Dapper是否可以自动扩展类成员

CS0103 dlibdotnet和www.example.com facerect不在上下文中

将列表字符串映射为逗号分隔字符串<>

如何注销Microsoft帐户?

. net依赖注入如何避免服务类中的新

如何将Kafka消息时间戳转换为C#中的日期和时间格式?

如何模拟耐久任务客户端在统一测试和获取错误在调度NewsListationInstanceAsync模拟设置

在具有主构造函数的类中初始化属性时出现警告

Azure Redis缓存与Entra ID身份验证

使用HttpResponseMessage中的嵌套列表初始化JSON

在实体框架中处理通用实体&S变更跟踪器

C#阻塞调用或await calling inside calling方法

升级后发出SWITCH语句

在等待OnGetAsync时打开Razor Page显示微调器

如何对特定异常使用Polly重试机制?

在构造函数中传递C#函数以用作EventHandler委托的订阅服务器

如何从原始图像到新创建的图像获得相同的特定 colored颜色 ,并且具有相同的 colored颜色 量和相同的宽度和高度?

如何在更新数据库实体时忽略特定字段?

外部应用&&的LINQ;左外部连接&类似于PostgreSQL的查询

更新实体框架上的被跟踪实体