【问题标题】:Is there any issue when accessing a globa/static dictionary using a static class?使用静态类访问全局/静态字典时是否有任何问题?
【发布时间】:2013-03-29 18:14:32
【问题描述】:

我为一个小项目创建了一个简单的验证过程。验证规则是作为类属性的属性创建的。

我有一个需要传递类类型的静态类。该方法将首先检查给定类的规则集是否已经在字典中,否则,它将使用反射来遍历每个属性。

使用这种方法会有什么问题吗?我担心在多线程环境中访问时可能会导致一些问题。

public static class Validator
{
    private static Dictionary<Type, ValidationRulesCollection> _validationRules = new Dictionary<Type, ValidationRulesCollection>();

    public static ValidationRulesCollection GetValidationRules(object obj)
    {
        return GetValidationRules(obj.GetType());
    }

    public static ValidationRulesCollection GetValidationRules(Type t)
    {
        ValidationRulesCollection rules = null;

        /* Check if the centralized rules repository already contains the rules for this class type */
        if (_validationRules.ContainsKey(t) == true)
        {
            rules = _validationRules[t];
        }
        else
        {
            /* Using reflection, get the list of properties for the class type */
            PropertyInfo[] properties = t.GetProperties();

            if (properties != null)
            {
                /* Iterate through each property info and check if it contains a validation rule */
                ValidationAttribute[] attribs = null;
                foreach (PropertyInfo property in properties)
                {
                    /* For each property, check if it contains a validation rule */
                    attribs = (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true);

                    if (attribs != null)
                    {
                        foreach (ValidationAttribute attrib in attribs)
                        {
                            if (rules == null)
                                rules = new ValidationRulesCollection();

                            /* Add the validation rule to the collection */
                            rules.Add(new ValidationRule(property, attrib));
                        }
                    }
                }
            }

            /* Add the rules collection to the centralized rules repository */
            if (rules.Count > 0)
                _validationRules.Add(t, rules);
            else
                throw new ArgumentNullException("The type " + t.ToString() + " does not have any ValidationAttributes");
        }

        return rules;
    }

    public static ValidationRulesCollection Validate(object obj)
    {
        /* Get the Validation Rules */
        ValidationRulesCollection rules = GetValidationRules(obj);

        /* Validate the rules */
        foreach (ValidationRule rule in rules)
        {
            rule.Validate(obj);
        }

        return rules;
    }
}

【问题讨论】:

标签: c#


【解决方案1】:

这可能会给您在多线程环境中带来麻烦。通常,Dictionary&lt;K,V&gt; 类不是线程安全的。除了数据损坏或正确性问题之外,在极少数情况下,如果一个线程在另一个线程上调整大小时遇到​​字典,您可能会遇到线程卡在循环中的情况,占用 100% 的 CPU。我曾经在一个生产网络应用程序中遇到过这种情况 - 调试起来并不有趣。

您可以在方法周围加一个锁,或者使用ConcurrentDictionary&lt;K,V&gt; 代替。

请注意,我们可以用不同的方式定义“线程安全”。如果您希望查找属性和属性的整个操作是原子的,您应该在方法周围加一个锁。但请注意,这会在应用程序中引入大量锁定,可能会损害性能。如果您可以在竞态条件下完成两次工作,并且只需要确保字典的行为正确,那么 ConcurrentDictionary 就是要走的路。

【讨论】:

  • 感谢您指出线程安全问题。如果我没记错的话,每当字典中的一个对象被一个线程使用时,第二个线程就必须等待?这是否正确?如果正确,是否会对性能造成重大影响?
  • 你甚至会得到(零星的)错误:你不能在没有锁定的情况下使用像if (!Contains) Add这样的代码:你对Add的调用可能会在Contains和@之间抛出重复的键异常987654327@ 在线程 1 上调用,线程 2 使用相同的键调用 AddConcurrentDictionary 也是如此。不过,使用索引器将“修复”这个问题:_validationRules[t] = rules;,因为最后一个线程会默默地覆盖前一个线程设置的任何值。
【解决方案2】:

Dictionary 不是线程安全的。而您的方法GetValidationRules 正在读写它。如果多个线程调用此方法,字典数据可能会损坏。为避免这种情况,请放置一个涵盖所有字典方法调用的lock(...){ ... }

【讨论】:

    猜你喜欢
    • 2019-06-07
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-07
    相关资源
    最近更新 更多