【问题标题】:Handling Different Sets of Data处理不同的数据集
【发布时间】:2012-02-18 13:17:03
【问题描述】:

我在整理代码时遇到了设计/架构问题。例如,我现在将数据存储在:

internal interface IProperty<TKey1, TKey2> : IDictionary<TKey1, TKey2> { }

internal class PropertyDictionary<TKey1, TKey2> : IProperty<TKey1, TKey2>

我在 PropertyDictionary 中实现 IDictionary。同样使用 PropertyDictionary 我可以拥有一个键,然后为值一个具有公共属性的不可变对象。然后我可以通过以下方式轻松引用数据:

        foreach (var data in inputData.Values)
        {
              var propertyValue = data.MyDataProperty;
        }

首先,这种方式存储数据似乎有很多开销,但更重要的是,现在当我需要扩展 PropertyDictionary 的功能时,例如包含 RetrievePrice,它变得复杂,因为我需要在接口中添加其他方法,然后创建一个新课程:

internal interface IAssetPriceData<in TKey1>
{
    double RetrievePrice(TKey1 key);
}

internal class PriceDictionary<TKey1, TKey2> : PropertyDictionary<TKey1, TKey2>, IAssetPriceData<TKey1>

因此,我应该如何构造我的代码以轻松存储不同类型的数据,然后轻松检索这些数据,以便我可以对正在存储的属性进行操作/执行计算的解决方案。

【问题讨论】:

  • 为什么不使用 .net 中提供的默认数据结构并通过扩展方法添加您需要的功能?
  • 如果我实现 IDictionary,我可以更改一些小事情,例如检查密钥是否存在。但即使我确实实现了字典,我有时仍然会遇到扩展其功能的问题。
  • 字典已经支持检查键是否存在,您可以在其中添加自己的扩展方法,而无需使用派生类型。
  • 经过进一步调查,我正在寻找的是属性包,它使我能够更好地存储和访问数据!

标签: c# oop architecture


【解决方案1】:

对于任何感兴趣的人,我写了一个类,有点像这里曾经描述过的类(如下)。我为某些 WPF 绑定场景分组相同类型的属性,并绑定到字典元素。我不想使用字典,因为框架会引发(并吃掉)key not found 异常。这个包装了一个字典并将字符串硬编码为键,尽管它可能被概括为适合这里描述的目的。主要需要注意的是索引器在未找到键时的行为——它返回默认的 T 而不是抛出异常。

/// 这个类表示一个用于绑定的通用集合 /// 哈希项永远不会为空,索引器永远不会抛出异常,缓存未命中时返回默认值 公共类 BindableHash : IEnumerable { #region 字段

    /// <summary>Current implementation of the hash is a dictionary</summary>
    private readonly Dictionary<string, T> _HashItems = new Dictionary<string, T>();

    #endregion

    #region Properties

    /// <summary>How many items are currently in the hash</summary>
    public virtual int Count { get { return _HashItems.Count; } }

    /// <summary>Indexer provides hashed (by string) lookup</summary>
    public virtual T this[string index]
    {
        get { return index != null && _HashItems.ContainsKey(index) ? _HashItems[index] : default(T); }
    }

    #endregion

    #region Constructors

    /// <summary>Default constructor initializes hash with no members</summary>
    public BindableHash() : this(null) { }

    /// <summary>Injected constructor seeds the list using the tuples passsed in</summary>
    public BindableHash(params Tuple<string, T>[] initialTuples)
    {
        foreach (Tuple<string, T> tuple in initialTuples ?? new Tuple<string, T>[] { })
        {
            Add(tuple);
        }
    }

    #endregion

    #region Methods

    /// <summary>Add a key-value pair to the hash</summary>
    public virtual void Add(string key, T value)
    {
        Add(new Tuple<string, T>(key, value));
    }

    /// <summary>Removes all items from the hash</summary>
    public virtual void Clear()
    {
        _HashItems.Clear();
    }

    /// <summary>Remove a particular value from the hash</summary>
    public bool Remove(string key)
    {
        return key != null && _HashItems.Remove(key);
    }

    #endregion

    #region Helpers

    /// <summary>Abstraction for adding a key value pair</summary>
    protected void Add(Tuple<string, T> tuple)
    {
        if (tuple != null && tuple.Item1 != null)
        {
            _HashItems[tuple.Item1] = tuple.Item2;
        }
    }

    #endregion

    #region IEnumerable<T> Members

    /// <summary>Define enumerator retrieval to allow enumeration over values</summary>
    public IEnumerator<T> GetEnumerator()
    {
        foreach (T value in _HashItems.Values)
        {
            yield return value;
        }
    }

    #endregion

    #region IEnumerable Members

    /// <summary>Impelementation for clients who cast this as non-generic IEnumerable</summary>
    /// <remarks>If you're not familiar with the black magic going on here, IEnmerable generic interface inherits from
    /// IEnumerable non-generic (legacy).  Both interfaces define GetEnumerator, and one returns a generic IEnumerator and the other
    /// a non-generic IEnumerator.  This one is the non-generic, and we want to 'hide' it for type safety purposes.  When you 
    /// do an explicit interface implementation, you create some kind of visibility purgatory.  This method is not private/protected
    /// because the interface is public, but it is also not a public method of this class.  The only way you can get to this guy is by casting
    /// BindableHash as IEnumerable (non-generic) and invoking the method that way.  Since that is possible to do, we have to implement the method,
    /// which we do by just invoking our generic one.  This is legal because of the fact that IEnumerator generic inherits from non-generic IEnumerator.
    /// Clear as mud?  You can ask me for a more detailed explanation, if you like --ebd</remarks>
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多