代码之家  ›  专栏  ›  技术社区  ›  Neil Anderson

询问成对对象最方便的方式是什么?

  •  6
  • Neil Anderson  · 技术社区  · 16 年前

    所以我必须设计一个类来处理成对对象的集合。对象之间有一对一的映射。我希望类的客户机在使用我的类之前已经建立了这个映射。

    我的问题是,什么是允许我的类用户向我提供这些信息的最佳方法?

    是要像这样收集一对吗?

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

    或者像这样分开收藏?

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

    还是有其他选择?

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

    我喜欢第二种,因为类型更原始,需要的工作更少,我不喜欢它,因为映射不显式。我得假设订单是正确的。

    请发表意见?

    12 回复  |  直到 16 年前
        1
  •  10
  •   George Stocker NotMe    16 年前

    在.NET 4中,您应该使用 Tuple<T1,T2> . 有关 Tuple 在MSDN中的类。

        2
  •  5
  •   JSBÕ±Õ¸Õ£Õ¹    16 年前

    如果您有权使用它,请使用 Tuple<T, R> . 如果不这样做,只需编写一个泛型 Tuple Pair 你自己的班级。我会避免使用 KeyValuePair 因为它很冗长而且与 Dictionary .

        3
  •  5
  •   Mikael Svenson    16 年前

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

    但我宁愿创建一个类来保存对您的对的引用。在我看来,这更具可读性,并且创建一个额外的类或结构来表达您的实际操作也不会有任何伤害。

    (伪码)

    class MyPair
    {
        public TypeA One;
        public TypeB Two;
    }
    
    MyClass(IEnumerable<MyPair> objects)
    

    有人提到 Tuple<,> 在一些答案中,它和keyValuePair一样可读,但是更灵活,因为它可以包含两个以上的参数。

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

    To Tuple or Not To Tuple

        4
  •  1
  •   Alex Humphrey    16 年前

    第一种方法是我的首选方法,因为一个序列可能比另一个序列长,第二种方法不维护所需的1:1映射。

        5
  •  1
  •   Christian Hayter    16 年前

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

        6
  •  1
  •   Hound    16 年前

    我当然喜欢第一个。正如您所说,显式的相关性,比第二个需要测试两个集合的长度相同的集合更不容易出错。当然,这可能实际上是适当的提供/双向/方式,取决于你正在建立的实际班级。

    有一点,如果您使用.NET 4.0,我建议您使用 Tuple<T1, T2> 而不是keyValuePair。

        7
  •  0
  •   KP.    16 年前

    我认为你必须选择1。必须有明确的关系,否则你只是在自找麻烦。

        8
  •  0
  •   Hamish Grubijan    16 年前

    我将使用第二个版本(因为它更简单)+注释+静态/动态检查。如果可以使用代码约定,请尝试确保集合的长度相同,而不是空。如果不是,那就用同样的方法 Debug.Assert 以及 if ... throw ArgumentException . 或者,您可以创建自己的包含该对的对象,但是如果您想为该对的成员使用泛型,则会变得更加困难。此外,当您创建一个要存储在容器中的对象时,必须正确地实现 GetHashCode , Equals 等等。第一本“有效的C”书上有一个项目。

    一般来说,我不喜欢设计方法签名。

        9
  •  0
  •   benjismith    16 年前

    我通常提供这两种方法,将keyValuePair构造函数委托给2-arg构造函数。两全其美。

        10
  •  0
  •   Paul Alexander    16 年前

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

    1. 如果他们已经将关系存储在Dictionary<gt;对象中,则可以按原样分发字典-不需要额外的代码。

    2. 如果它们使用自己的自定义存储,那么使用yield语句在IEnumerable中为您提供keyValuePair非常容易。

    像这样:

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

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

    顺便说一下,如果将方法声明为泛型而不是硬编码的keyValuePair,可能会得到最好的服务。

    MyClass<TKey,TValue>( IEnumerable<KeyValuePair<TKey,TValue>> pairs );
    
        11
  •  0
  •   CodexArcanum    16 年前

    可能值得考虑一下为什么要公开一个Enumerable。您可以使用一个add(object a,object b)方法,它完全隐藏了处理对的内部方法。然后,客户可以设置自己的方法,将关系作为集合或单独添加到其中。

    当然,如果您仍然需要一个采用可枚举的方法,那么第一个选项可能是最好的:显式关系。但您可以考虑使用或生成一个元组或对类型来代替keyValuePair,前提是它们之间的关系不是价值本质的关键。

        12
  •  0
  •   Dan Tao    16 年前

    如果你做了什么 ?

    // 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);
    
    推荐文章