c#字典-“值未在预期范围内" [英] c# Dictionary - "Value does not fall within the expected range"

查看:294
本文介绍了c#字典-“值未在预期范围内"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的WP7/8应用中,有时我会从用户那里收到以下错误消息(在此处无法重现该问题).

in my WP7/8 app I get sometimes the following error message from my users (can't reproduce the issue here).

[Type]:[ArgumentException]
[ExceptionMessage]:[Value does not fall within the expected range.]
[StackTrace]:[
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(Date key, WorkDay value, Boolean add)
   at MyProject.Core.Data.WorkDayCache.GetWorkDay(Date date, Boolean returnCorrected)
   at MyProject.Core.Calculations.CalculationHelper.WorkTimeDay(Date date)
   at MyProject.WP.UI.InfoBoxes.IBWorkTimeToday.UpdateMinute()
   at MyProject.WP.UI.InfoBoxes.IBWorkTimeToday.Update()
   at MyProject.WP.UI.MainPage.UpdateInfoBoxes()
   at MyProject.WP.UI.MainPage.ButtonStart_Click(Object sender, RoutedEventArgs e)
   at System.Windows.Controls.Primitives.ButtonBase.OnClick()
   at System.Windows.Controls.Button.OnClick()
   at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
   at System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
   at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
]
[InnerException]:[none]

这是GetWorkDay方法的代码:

Here is the code of the GetWorkDay method:

/// <summary>
/// Returns the cached work day for a given date
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
public WorkDay GetWorkDay(Date date, bool returnCorrected = true)
{
    // return the cached value in case it is cached and the filter is disabled
    if (!TagFilter.IsFilterEnabled)
    {
        if (_cachedWorkDays.ContainsKey(date))
        {
            if (returnCorrected)
            {
                var correctedWorkDay = new TimeCalculatorInterface().GetCorrectedWorkDay(_cachedWorkDays[date]);
                return correctedWorkDay;
            }
            return _cachedWorkDays[date];
        }
    }

    // nothing cached, thus get the result and cache it
    var workDays = _databaseController.Wait().GetWorkDays(date, date, false);
    if (workDays != null && workDays.Count > 0)
    {
        if (!TagFilter.IsFilterEnabled)
            _cachedWorkDays.Add(date, workDays[0]);

        // correct the work day times with the break times if enabled
        if (returnCorrected)
        {
            var correctedWorkDay = new TimeCalculatorInterface().GetCorrectedWorkDay(workDays[0]);
            return correctedWorkDay;
        }

        return workDays[0];
    }

    return new WorkDay();
}

我的主要问题是我不知道是什么导致异常.最近两天给我的印象是,此消息仅表示它试图将一个键值对添加到已存在该键的字典中.但是在这种情况下,此缓存会在密钥是否已经存在之前立即进行检查,并返回缓存的值.我编写了一些详细的单元测试,其中包含数千个插入内容,但没有任何反应.

My main issue is that I don't understand what causes the exception. I've been under the impression for the last two days that this message just means that it tries to add a keyvaluepair into the dictionary where the key already exists. But this cache checks right before whether the key already exists and returns the cached value in this case. I wrote a couple of detailed unit tests with thousands of inserts and nothing happened.

在堆栈跟踪中奇怪的是,在GetWorkDay()Dictionary2.Insert()之后立即被调用的事实.但是我发现所有存在重复键问题的堆栈跟踪都在调用Dictionary2.Add()之前(实际上我在代码中这样做是因为我无法直接调用Insert().

What's odd in the stack trace is the fact that right after GetWorkDay() Dictionary2.Insert() is called. But all the stack traces I found that have a duplicate key issue call the Dictionary2.Add() before (which I actually do in the code because I can't call Insert() directly.

那么我有什么想念的东西会抛出这个异常吗?

So is there anything I miss which might throw this exception?

还有一些要知道的事情:

Some more things to know:

_cachedWorkDays是唯一的键类型为Date且值类型为WorkDay的词典

_cachedWorkDays is the only dictionary there with key type Date and value type WorkDay

Date是我自己对日期的实现(需要比DateTime提供的更多的日期处理方法.此外,我想确保DateTime中的时间部分不会影响我的日期处理).当我使用Date作为字典中的键时,它需要使用Equals和GetHashCode重写,如下所示)

Date is my own implementation of a date (Needed some more methods for working with dates than DateTime provided me. Additionally, I wanted to make sure the time part in DateTime doesn't influence my date processings). As I use Date as key in the dictionary it requires an Equals and GetHashCode override which is as follows)

public static bool operator ==(Date d1, Date d2)
{
    return d1.Day == d2.Day && d1.Month == d2.Month && d1.Year == d2.Year;
}   

public override bool Equals(object obj)
{
    if (obj.GetType() == this.GetType())
    {
        Date obj1 = (Date)obj;
        return obj1 == this;
    }
    return false;
}

public override int GetHashCode()
{
    return (Year*100 + Month)*100 + Day;
}

我们非常感谢您的帮助.

Any help is highly appreciated.

关于斯蒂芬

推荐答案

可能的原因1:并发问题.在线程A执行_databaseController.Wait()时,线程B将那天添加到了缓存中,在线程A唤醒后,您将看到完全相同的异常.

Possible reason #1: concurrency issue. While thread A is executing _databaseController.Wait(), thread B has added that day to the cache, after the thread A wakes up you'll see exactly the same exception.

可能的原因2:您的Date类是可变的.使用可变数据类型作为键将完全破坏字典.请注意,System.DateTime是(a)不可变(b)结构(c)实现IEquatable<DateTime>.

Possible reason #2: your Date class is mutable. Using mutable data types as keys will completely screw the dictionary. Please note System.DateTime is (a) immutable (b) struct (c) implements IEquatable<DateTime>.

P.S.使用dict.TryGetValue(..) API比dict.ContainsKey(..)和后续的dict[..]

P.S. Using dict.TryGetValue(..) API is more efficient than dict.ContainsKey(..) and subsequent dict[..]

这篇关于c#字典-“值未在预期范围内"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆