【问题标题】:What is the most inuitive way to ask for objects in pairs?成对询问对象最直观的方式是什么?
【发布时间】:2010-07-12 19:27:43
【问题描述】:

所以我必须设计一个适用于成对对象集合的类。对象之间存在一对一的映射。我希望班级的客户在使用我的班级之前已经建立了这个映射。

我的问题是让我的班级用户向我提供这些信息的最佳方式是什么?

是要这样的对的集合吗?

MyClass(IEnumerable<KeyValuePair<Object, Object>> objects)

或者像这样单独的集合?

MyClass(IEnumberable<Object> x, IEnumerable<Object> y)

或者还有其他选择吗?

我喜欢第一个,因为关系是明确的,我不喜欢它,因为它给客户带来了额外的工作。

我喜欢第二个,因为类型更原始,需要的工作更少,我不喜欢它,因为映射不明确。我必须假设顺序是正确的。

请给点意见?

【问题讨论】:

  • 出于同样的原因,我喜欢第一个,关系是明确的。由于 KeyValuePair 在整个框架中很常见,因此我认为没有任何“额外工作”它可能具有的一个缺点是 KeyValuePair 推断 T2 以某种方式由 T1 键入,如果它们之间的关系更加对称,您可以滚动自己的类型(即 Pair)。

标签: c# usability


【解决方案1】:

在 .NET 4 中,您应该使用 Tuple&lt;T1,T2&gt;。有关 MSDN 上 Tuple 课程的更多信息。

【讨论】:

  • 为了争论。为什么要使用 Tuple 而不是您自己的配对类?
  • @korbinian -- 这就是我的想法,但 MSDN 包含一个指向“以前版本”的链接,其中包括 .NET 3.5。不幸的是,那里的评论(我没有看)如实表明它只是 .NET 4 的现实。
  • @Mikael - 这样您就不必维护已经存在的类。但是,如果您需要的不仅仅是一个简单的容器,那么它可能是值得的。
  • @tvanfosson,我明白你的意思,但我认为一个有好名字的类更好,至少如果它被用于多个地方。我几乎只将 Tuple 用于返回类型以避免“输出”,并且仅当输出在一个地方使用时。有点火,然后忘记。就像我在字典循环中使用 KeyValuePair 一样。
【解决方案2】:

如果您有权访问它,请使用Tuple&lt;T, R&gt;。如果你不这样做,只需编写一个通用的TuplePair 你自己的类。我会避免使用KeyValuePair,因为它很冗长并且与Dictionary 有关联。

【讨论】:

  • 另外,上次我检查过,KeyValuePair 不会序列化为 XML,所以如果这对您很重要,这是另一个不使用它的好理由。
【解决方案3】:

我更喜欢你提到的两个 KeyValuePair,因为它更具表现力并保持对象之间的关系。

但我宁愿创建一个包含对您的配对的引用的类。在我看来,这更具可读性,并且创建一个额外的类或结构来表达您的实际操作永远不会有坏处。

(伪代码)

class MyPair
{
    public TypeA One;
    public TypeB Two;
}

MyClass(IEnumerable<MyPair> objects)

在某些答案中提到了Tuple&lt;,&gt;,它与 KeyValuePair 一样可读,但更灵活,因为它可以包含两个以上的参数。

[编辑 - 睡个好觉后更深入地了解元组/类]

To Tuple or Not To Tuple

【讨论】:

  • MyPair 为什么要实现 IEnumerable?
  • @Alex,因为它不应该 :) 你是对的,我显然需要睡觉。
  • 别担心,伙计——我可以和睡眠有关:)
  • 他们让你睡在你的公司?!
  • @Jay,欧洲 :) 晚上 10 点,我的孩子太早把我吵醒了。但我想我可以在工作时睡觉,因为几乎每个人都在度假。
【解决方案4】:

第一种方法是我的首选方法,因为使用第二种方法,一个序列可能比另一个更长 - 它不能保持所需的 1:1 映射。

【讨论】:

    【解决方案5】:

    在我看来,第二种选择让您和客户都有更多的工作要做。第一种选择更安全,更难出错。我每次都会选择第一个选项或类似的选项。

    【讨论】:

      【解决方案6】:

      我当然更喜欢第一个。正如您所说,相关性是显式的,并且比您需要测试两个集合具有相同长度的第二个更不容易出错。当然,提供 /both/ 方式实际上可能是合适的,具体取决于您正在构建的实际课程。

      有一件事,如果您使用 .NET 4.0,我建议使用 Tuple&lt;T1, T2&gt; 而不是 KeyValuePair。

      【讨论】:

        【解决方案7】:

        我认为您必须选择选项 1。必须涉及明确的关系,否则您只是自找麻烦。

        【讨论】:

          【解决方案8】:

          我会使用第二个版本(因为它更简单)+ cmets + 静态/动态检查。如果您可以使用代码协定,请尝试确保集合的长度相同,而不是 null。如果不是,则对Debug.Assertif ... throw ArgumentException 执行相同操作。或者,您可以创建自己的包含该对的对象,但是如果您想为该对的成员使用泛型,则变得更加困难。此外,当您创建一个打算存储在容器中的对象时,您必须正确实现GetHashCodeEquals 等。第一本“Effective C#”书对此有一个项目。

          作为一般规则,我不喜欢过度设计方法签名。

          【讨论】:

            【解决方案9】:

            我通常提供两者,将 KeyValuePair 构造函数委托给 2-arg 构造函数。两全其美。

            【讨论】:

            • 只是好奇——我知道你如何通过 Zip 从两个 arg 方法转到一个 arg——你如何反过来做?
            • public MyClass(KeyValuePair pair) : this(pair.Key, pair.Value) { }
            【解决方案10】:

            我喜欢第一种方法有两个原因。

            1. 如果他们已经将他们的关系存储在 Dictionary 对象中,他们可以直接交出字典 - 不需要额外的代码。

            2. 如果他们使用自己的自定义存储,那么使用 yield 语句在 IEnumerable 中为您提供 KeyValuePairs 真的很容易

            类似这样的:

            IEnumerable<KeyValuePair<Object,Object>> GetMappedPairs()
            {
                foreach( var pair in _myCustomData )
                {
                    yield return new KeyValuePair{Key = pair.ID, Value = pair.Data};
                }
            }
            

            使用您的方法的开发人员不容易理解选项 2,因此需要文档和 cmets 来解释如何使用它。

            顺便说一句,最好将您的方法声明为泛型而不是硬编码 KeyValuePair

            MyClass<TKey,TValue>( IEnumerable<KeyValuePair<TKey,TValue>> pairs );
            

            【讨论】:

              【解决方案11】:

              可能值得考虑一下为什么要公开枚举。您可以使用 Add(Object a, Object b) 方法,该方法完全隐藏您处理对的内部方式。然后,客户端可以设置自己的方式来将关系添加到它的集合或单个。

              当然,如果您仍然需要采用可枚举的方法,那么第一个选项可能是最好的:显式关系。但是您考虑使用或制作一个 Tuple 或 Pair 类型来代替 KeyValuePair,假设它们之间的关系不是 Key to Value 的性质之一。

              【讨论】:

                【解决方案12】:

                现在如果你做了类似这个的事情呢?

                // The client can choose to put together an IEnumerable<...> by hand...    
                public MyClass(IEnumerable<KeyValuePair<object, object>> pairs)
                {
                    // actual code that does something with the data pairs
                }
                
                // OR the client can pass whatever the heck he/she wants, as long as
                // some method for selecting the Xs and Ys from the enumerable data is provided.
                // (Sorry about the code mangling, by the way -- just avoiding overflow.)
                public static MyClass Create<T>
                (IEnumerable<T> source, Func<T, object> xSelector, Func<T, object> ySelector)
                {
                    var pairs = source
                        .Select(
                            val => new KeyValuePair<object, object>(
                                xSelector(val),
                                ySelector(val)
                            )
                        );
                
                    return new MyClass(pairs);
                }
                

                这将允许客户编写如下代码:

                // totally hypothetical example
                var stockReturns = StockReturns.Create(prices, p => p.Close, p => p.PrevClose);
                

                【讨论】:

                  猜你喜欢
                  • 2017-12-11
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-07-13
                  • 1970-01-01
                  • 2014-06-29
                  • 1970-01-01
                  • 2010-11-08
                  • 2017-07-15
                  相关资源
                  最近更新 更多