只读集合属性的类设计

时间:2016-04-28 01:12:49

标签: c#

我有一个IReadOnlyDictionary<string, MyEnum>集合需要传递给一个类,以便将其包含在MyEnum中(注意MyEnum?但不是IReadOnlyDictionary<string, MyEnum>)。

我想出了两个设计:

  1. 将包装延迟到public class MyClass { private readonly IEnumerable<KeyValuePair<string, MyEnum?>> _kvps; public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps) { _kvps = kvps; } public IReadOnlyDictionary<string, MyEnum> Kvps { get { var filtered = from kvp in _kvps where kvp.Value.HasValue select kvp; return new ReadOnlyDictionary<string, MyEnum>( filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value); } } } ,直到属性访问:

    public class MyClass
    {
        public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
        {
            Kvps = ToReadOnly(kvps);
        }
    
        public IReadOnlyDictionary<string, MyEnum> Kvps { get; }
    
        private static IReadOnlyDictionary<string, MyEnum> ToReadOnly(
            IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
        {
            var filtered = from kvp in kvps
                           where kvp.Value.HasValue
                           select kvp;
            return new ReadOnlyDictionary<string, MyEnum>(
               filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
        }
    }
    
  2. 急切地评估构造函数中的集合

    MyClass.Kvps
  3. 框架设计指南的constructor design部分表明,应该在构造函数中完成最少的工作,因此我选择了第一种方法。但是,这意味着每次调用_kvps都会触发MyClass的副本,这不是理想的。

    我想知道哪种方法更好(或者有其他方法):

    • 内存效率(理想情况下,只有一个副本集存储在KeyValuePair
    • 性能(属性访问速度快,不应触发[ {"name": "SpanningTree", "size": 3416}, {"name": "SpanningTree2", "size": 7312} ] s的副本)

2 个答案:

答案 0 :(得分:1)

编辑:如果您想要最新的源值,最好的方法是实现自己的实现IReadOnlyDictionary的类。使用ReadOnlyDictionary<string, MyEnum?>的私有字段对其进行初始化。每个调用都将执行查找,如果键存在并且HasValue,则返回值。

请注意,此实现取决于对作为IReadOnlyDictionary传入的原始值的引用,以避免必须复制值。

public class MyReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue> where TValue : struct
{
    // other methods to implement here...

    public MyReadOnlyDictionary(IReadOnlyDictionary<TKey, TValue?> kvps)
    {
        _kvps = kvps;
    }

    private IReadOnlyDictionary<TKey, TValue?> _kvps;

    new public TValue this[TKey key]
    {
        get
        {
            TValue? val = _kvps[key];
            if (val.HasValue)
                return val.Value;
            throw new KeyNotFoundException();
        }
    }
}

答案 1 :(得分:1)

在这两个要求中 - 不要复制键值对并且不要存储两个副本 - 你必须打破一个。

是什么原因让我们看到这一点,并认为必须是一个解决方案,我们看到TValueTValue?,我们的思想希望看到它们属于相同的类型。但它们不是同一类型。

如果您想象TValueTValue?而不是intstring这两种不同类型,例如List<string> GetStringsFromNonNegativeInts(List<int> ints) { return ints.Where(i=>i>-1).Select(i=>i.ToString()).ToList(); } TValue?,我们想要投射更清楚过滤时,一个集合到另一个集合中。例如,

TValue

与尝试将一组TValue过滤到一组TValue?的情况完全相同,即使没有字典也是如此。它更难看。 {{1}}和{{1}}代码使我们失明。

只有两种方法可以做到这一点。一种是每次复制,另一种是保持两个列表同步。