【问题标题】:Implementing a Tag property on entity classes在实体类上实现 Tag 属性
【发布时间】:2010-08-23 23:27:18
【问题描述】:

当我在类库中创建实体时,我倾向于添加一个Tag 属性,用户可以使用它并扩展库以随对象存储任意数据。现在我正在寻找在我的类库中实现这种Tag 属性的最佳方法,以及原因。

在 System.Windows.Forms 中,Microsoft 使用object Tag { get; set; } 作为签名,但它看起来过于局限,因为任何时候都只有一个人可以使用该标签。

我也想过HashTable Tag { get; } 允许任何人通过键设置和检索任何数据,但对于类库来说这似乎太“暴露”了。那么IDictionary Tag { get; } 将是一个更好的选择,但两者都允许任何人清除我想要避免的整个字典。再说一次,HashTable 和 IDictionary 都只允许您使用 object 实例,其中通用的东西可能是更好的选择。但Dictionary<?> Tag { get; } 显然不适用于所有可能的消费者。

那么,该走哪条路?

编辑: 正如下面的 Timwi 正确建议的那样,我不希望不同的用户类能够相互干扰。我假设有很多实体类,而只有少数类想要存储关联数据。

【问题讨论】:

    标签: c# .net tags properties


    【解决方案1】:

    您的要求之一似乎是访问实体对象的各个线程或进程不应看到彼此的私有数据。恐怕这是一个很好的迹象,表明私有数据不应该在他们共享的实体对象中。相反,每个进程都应该有自己的私有数据。它实际上不一定是in实体对象本身,但它可以通过私有字典与实体对象相关联:

    private Dictionary<Entity, object> myPrivateEntityData = new ...;
    

    此外,由于它现在是进程私有的,并且进程大概知道它想与每个实体关联什么样的数据,您现在可以使其完全类型安全。

    private Dictionary<Entity, SuperSecretSpecialData> myPrivateEntityData = new ...;
    
    private sealed class SuperSecretData {
        public bool     NoOne;
        public int      ElseBut;
        public string   MeCan;
        public DateTime SeeThis;
    }
    

    必须先检查每个实体是否在字典中会带来一些痛苦,但您也可以解决这个问题。我个人使用一个类AutoDictionary,它只是扩展Dictionary,以便在对象丢失时自动创建对象:

    public sealed class AutoDictionary<TKey, TVal> : Dictionary<TKey, TVal> where TVal : class, new()
    {
        public new TVal this[TKey key]
        {
            get
            {
                if (!ContainsKey(key))
                    Add(key, new TVal());
                return base[key];
            }
            set
            {
                base[key] = value;
            }
        }
    }
    
    private AutoDictionary<Entity, SuperSecretSpecialData> myPrivateEntityData = new ...;
    

    然后您可以轻松访问myPrivateEntityData[someEntity].NoOne(等),它会正常工作并且永远不会因为密钥不存在而引发异常,但如果您想要,您仍然可以使用ContainsKey > 检查它是否存在。

    【讨论】:

    • 但是想象一下这样一种可能的情况:有很多实体对象,但只有一个或几个用户类存储相关数据。为每个实体拥有一个小字典会比为每个用户拥有一个大字典更快吗?是的,这会产生许多小字典。也许,在用户类可能想要存储几乎每个实体的引用的假设下,可以找到一些折衷方案?
    【解决方案2】:

    可能是这样的吗?

    
    public class Taggable :ITaggable
        {
            private IDictionary<string, object> _tags = new Dictionary<string, object>();
            public void AddTag(string key, object tag)
            {
                _tags.Add(key,tag);
            }
    
            public bool IsTag(string key)
            {
                return _tags.ContainsKey(key);
            }
    
            public T GetTag<T>(string key)
            {
                return (T) _tags[key];
            }
            public void RemoveTag(string key)
            {
                _tags.Remove(key);
            }
        }
    

    虽然我没有包含,但是四个方法都在界面上。

    没有人可以“滥用”该集合,因为他们需要知道密钥。

    【讨论】:

      【解决方案3】:

      您可以扩展 IDictionaryDictionary 以使其可变。但是,有些事情告诉我,您通常可能会遇到这个错误。松散类型的集合在交付端总是很有趣...

      这只是我的 2c,有点主观,但除非必要,否则我会避免使用松散的类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-27
        • 2011-04-17
        • 2011-09-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多