【问题标题】:Do you accept interfaces as constructor parameters?你接受接口作为构造函数参数吗?
【发布时间】:2009-01-09 15:19:33
【问题描述】:

Krzysztof's 的建议是否适用于构造函数?如果是这样,您如何正确实施?

我们建议对输出和属性使用 Collection、ReadOnlyCollection 或 KeyedCollection,对输入使用接口 IEnumerable、ICollection、IList。

例如,

public ClassA
{
    private Collection<String> strings;
    public Collection<String> Strings { get { return strings; } }
    public ClassA(IEnumerable<String> strings)
    {
        this.strings = strings; // this does not compile
        this.strings = strings as Collection<String>; // compiles (and usually runs?)
    }
}

【问题讨论】:

    标签: .net generics constructor interface robustness


    【解决方案1】:

    你应该避免向下转换;在您的示例中,我建议您的构造函数参数的类型应匹配(应与)您的成员数据的类型(即 either Collection&lt;String&gt; or IEnumerable&lt;String&gt;)。

    或者还有 Marc 的解决方案,这是不同的:因为 Marc 的解决方案意味着您的成员数据不仅是不同的类型,而且还是不同的实例(即,如果您修改成员数据,那么您正在修改原始集合,而不是编辑原始集合本身;类似地,如果在您制作副本后修改了原始集合,则您的本地副本/成员数据不包括对原始集合的后续更改。

    【讨论】:

      【解决方案2】:

      您不应该使用 as 版本 - 您应该接受并存储像 IList&lt;T&gt; 这样可重复的内容,或者创建一个新的本地数据集合:

      this.strings = new Collection<string>();
      foreach(string s in strings) { this.strings.Add(s); }
      

      实际上,我自己会使用List&lt;T&gt;;那么你可以这样做(虽然这不是使用List&lt;T&gt;的原因):

      this.strings = new List<string>(strings);
      

      【讨论】:

      • 我喜欢在内部使用 IList 的想法...接受数组(即 IEnumerable)并获得强类型泛型集合的方法很少。
      • 注意数组也实现了 IList 和 ICollection;但是是的,很容易从 IEnumerable 获取强类型集合
      【解决方案3】:

      我认为如果可能的话,应该避免向下转换。如果该类将输入存储为具体类“Collection”(这意味着该类与“Collection”一起使用,那么我认为只接受“Collection”类型的输入而不是接口对应项更自然。

      这将向下转换(如果需要)的责任转移给了消费者,如果他确实向下转换,他们应该知道他在做什么。

      另一方面,我会说接受输入作为接口比具体类更好,因为它可以更轻松地灵活地输入模拟对象。但是,这需要类的内部依赖于接口而不是具体类(因此在示例中,成员变量将是 IEnumerable 而不是 Collection)。

      我同意 yapiskan 的观点,即 Marc 的解决方案实际上通过创建输入副本改变了用法,因此职责发生了变化:

      之前:输入在消费者和此类之间始终共享。因此,对输入的更改在消费者和此类之间“共享”

      After:在调用构造函数之后,这个类对输入的理解与消费者分离。

      【讨论】:

        【解决方案4】:

        如果您存储的是 Collection,那么我更喜欢将 ICollection 作为输入。

        【讨论】:

          【解决方案5】:

          为什么不接受 IEnumerable&lt;String&gt; 类型的参数并将其投射到检索中?

          public ClassA
          {
              private IEnumberable<String> strings;
          
              public Collection<String> StringCollection {
                  get { return (Collection<String>) strings; }
              }
          
              public ClassA(IEnumerable<String> strings)
              {
                  this.strings = strings; 
              }
          }
          

          【讨论】:

          • 演员表可能并不总是有效,对吧?特别是如果 IEnumerable 没有结束(使用 Random 的实现)或者源是外部的并且可能超时(网络资源、Web 服务等)。
          【解决方案6】:

          我同意佩奇的观点,有点。

          我同意您应该将 IEnumerable 作为输入传递(这样您就支持任何可枚举的集合)。

          但是你在上面对 StringCollection 属性所做的事情对我来说没有意义 - 你正在向下转换,这是行不通的。

          -马特

          【讨论】:

            【解决方案7】:

            这可能是关于不要暴露太多你的实现。理想情况下,如果您正在设计一个公共 API,您应该只公开最低限度的实现。如果你返回一个完整的 List 接口,那么公共 API 的用户将会有很多方式以你可能没有想到的方式来弄乱你的类的内部。

            ----编辑----

            【讨论】:

              猜你喜欢
              • 2014-02-09
              • 2019-03-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-02-23
              • 2016-09-03
              相关资源
              最近更新 更多