代码之家  ›  专栏  ›  技术社区  ›  Erik Forbes

如果不应该将集合返回给调用者,那么应该如何将数据集合返回给调用者?

  •  5
  • Erik Forbes  · 技术社区  · 16 年前

    IDictionary<string, string> .

    编辑

    我还听到了其他一些原因,但我一时想不起来——这些是我目前处境中最重要的原因。

    编辑 :更多说明:我遇到的问题是,我正在构建一个API,因此我无法控制调用此函数的客户端。克隆字典不是一个问题,但我正在努力保持我的API尽可能干净。使用Add和Remove等方法返回字典意味着可以或应该修改集合,但事实并非如此。这里的修改是没有意义的,因此我不想通过返回类型的接口公开该功能的承诺。


    决议 IDictionary ,但我将编写一个方法 ToDictionary 这将在一段时间内返回数据 词典 . 它将实施 IEnumerable<KeyValuePair<TKey, TValue>> 为了访问枚举上的标准LINQ操作。现在我只需要自定义字典类型的名称…=)谢谢大家。

    10 回复  |  直到 16 年前
        1
  •  7
  •   Paul Butcher    16 年前

    这种限制的主要原因是,如果类返回 成员

    也就是说,您可能希望更仔细地思考为什么要退回此收藏。您希望调用类能够对数据执行什么操作?是否可以通过向类中添加方法而不是返回集合(例如,myobj.getvalueFromKey而不是myobj.getdictionary()[s])来实现此功能?返回一个只公开您想要的信息的对象,而不是简单地返回集合(例如MyLookupTable MyClass::getLookupTable()而不是IDictionary MyClass::getLookupTable()),可能更合适。

    如果您无法控制调用方,并且必须返回给定类型的集合,那么它应该是成员集合的副本,或者是被调用方不存储的新集合。

        2
  •  10
  •   Michael Borgwardt    16 年前

    关于回归的普遍共识 方法调用的集合类型为 不可以。

    我第一次听到这个,对我来说这似乎是一个愚蠢的限制。

    我理解其中的原因 政策

    编辑: 您反对返回集合的原因是特定的潜在问题,这些问题可以是特定的地址(通过返回只读包装),而不必对返回集合进行全面限制。但据我所知,该集合实际上是由该方法构建的——在这种情况下,调用方所做的更改不会影响任何其他内容,因此您不必真正担心,也不应过度限制调用方对专门为其创建的对象所能做的事。

        3
  •  1
  •   Janusz Daniel Rindt    16 年前

    在我看来,如果更改返回的集合可能会产生副作用,那么返回集合只是一个问题,例如,多个函数使用同一集合。

    如果您只是创建集合,而不是通过返回集合来公开类中的数据,我认为只返回字典是可以的

        4
  •  0
  •   Scott Saunders    16 年前

    我从来没有听过这个建议。如果做得不好,线程安全性可能会有问题,但如果需要,可以解决这个问题。

        5
  •  0
  •   No Refunds No Returns    16 年前

    为此,请查看ReadOnlyCollection()。将返回类型和上一条语句更改为

    return new ReadOnlyCollection(whateverYouWereReturningBefore);
    
        6
  •  0
  •   Jeremy McGee    16 年前

    也许这是一种困惑 只读集合 (即不可变集合)?如果是这样的话,那就有问题了 an excellent series of posts by Eric Lippert 这是关于如何构建这些的详细信息。

    如果知道数据结构永远不会改变,那么对它进行推理就容易多了。由于无法修改它们,因此它们是自动线程安全的。由于它们无法修改,您可以维护该结构过去的快照堆栈,然后突然间撤销重做实现变得微不足道。

        7
  •  0
  •   jk.    16 年前

    退票怎么样 IEnumerable<T> ,调用方就可以轻松地通过linq过滤结果,而无需改变原始结构。

    显然,对于一本字典来说,这将是 IEnumerable<KeyValuePair<T,U>>

    编辑:对于查找,您可能需要ToLookup()扩展名和ILookup

        8
  •  0
  •   Kyle Trauberman pestades    16 年前

    我通常返回一个数据数组和一个集合类型。例如,在C#中,许多集合实现了.toArray()方法,而对于那个些并没有实现的集合,可以使用lambdas检索数组。

    编辑

    看到你对“不退款不退货”回答的评论。如果要返回字典,数组可能不适合您。在这种情况下,我建议返回一个接口,而不是一个具体的实现。

    public IDictionary<string, object> MyMethod()
    {
        Dictionary<string, object> myDictionary = new Dictionary<string, object>();
    
        // do stuff here
    
        return myDictionary;
    }
    

    您可能需要实现自己的只读字典类,并在必要的方法中抛出异常以防止添加等。

    在C#(同样,例如)(不是一个完整的解决方案)中:

    public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        private IDictionary<TKey, TValue> _innerDictionary;
    
        public ReadOnlyDictionary(IDictionary<TKey, TValue> innerDictionary)
        {
            this._innerDictionary = innerDictionary;
        }
    
        public void Add(TKey key, TValue value)
        {
            throw new NotImplementedException();
        }
    
        public bool Remove(TKey key)
        {
            throw new NotImplementedException();
        }
    
        public void Add(KeyValuePair<TKey, TValue> item)
        {
            throw new NotImplementedException();
        }
    
        public void Clear()
        {
            throw new NotImplementedException();
        }
    
        public bool IsReadOnly
        {
            get { return true; }
        }
    
        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            throw new NotImplementedException();
        }
    
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return _innerDictionary.GetEnumerator();
        }
    
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _innerDictionary.GetEnumerator();
        }
    }
    
        9
  •  0
  •   Robert Rossney    16 年前

    我听说不允许这种行为的原因是,要由客户端使用(但不修改)的集合或字典类型暴露了太多的行为,使调用方产生了可以修改该类型的错觉。

    可以

    按照同样的逻辑, DataTable.Select() DataRow[] ,因为调用方不仅可以操纵该数组的成员资格,还可以更改底层数据!

    ToDictionary() 方法:这样做可能带来什么好处?

    确实,返回不可变对象使您可以在不更改API的情况下实现interning。但这是我能想到的唯一优势。

        10
  •  0
  •   supercat    14 年前

    使用可变类对象传递数据的一个主要问题是,每个可变对象包含两种主要的状态:

    1. 其所有字段的内容以及由此引用的对象。
    2. 存在于它的所有引用的集合,以及可以使用这些引用执行的操作。

    如果方法接受可变对象(无论是集合还是其他对象)作为参数,并且其协定指定它将以某种方式对其进行变异(例如,向集合添加项),但不保留对它的任何引用,然后调用方将知道在方法调用之后存在于该对象的引用集将与之前相同。如果调用方除了将对象传递给这样的方法之外从不向外界公开对象,那么跟踪存在的引用将很容易。

    另一方面,如果方法将可变对象返回给调用方,则跟踪传入和传出的对象可能存在的引用可能很困难或不可能,除非每个调用方接收到不同的可变对象。让被调用函数在每次被调用时创建一个新的可变对象,并在适当的情况下用数据填充该对象,当然是一种可行的方法,但通常最好让调用方创建新对象。这样,调用者就可以在适当的时候回收对象(提高性能),从而更清楚地了解发生了什么。例如,如果 Customer 是一个可变类,其中一个可以:

      Customer myCustomer = Database.GetCustomer("Fred Smith");
    

    目前尚不清楚是否要对 myCustomer

      Customer myCustomer = new Customer;
      Database.LoadCustomer(myCustomer, "Fred Smith");
    

    更清楚的是 我的客户 未附加到数据库(或其他任何内容)。