【问题标题】:Nullable Property throwing NullReferenceException on .HasValueNullable 属性在 .HasValue 上引发 NullReferenceException
【发布时间】:2012-11-16 19:56:12
【问题描述】:

这行(C#)代码

if (!currentLap.S1.HasValue)

给我

System.NullReferenceException:对象引用未设置为对象的实例。

如果我确定 currentLap 变量已被实例化(因为它之前已经被使用了几行并且它是一个局部变量)并且它具有以下属性:

private double? _s1;

[DefaultValue(null)]
[JsonConverter(typeof(ShortDoubleConverter))]
public double? S1
{
    get { return _s1; }
    set { _s1 = value; }
}

它怎么可能抛出 NullReferenceException?会不会和Release模式的优化有关?

谢谢, 史蒂夫

编辑:

这里是完整的方法代码。

public void Update(DriverData driverData)
    {
        LapInfo currentLap = this.CurrentLap;

        if (currentLap != null &&
       this.LastDriverData != null &&
       driverData.TotalLaps != this.LastDriverData.TotalLaps &&
       driverData.InPits &&
       driverData.Speed < 10 &&
       !this.LastDriverData.InPits)
        {
            currentLap.Escaped = true;
        }    

        this.LastDriverData = driverData;

        if ((currentLap == null || currentLap.Lap != driverData.LapNumber) &&
            !this.Laps.TryGetValue(driverData.LapNumber, out currentLap))
        {
            currentLap = new LapInfo() { Lap = driverData.LapNumber, Parent = this, Class = driverData.Class };
            this.Laps.Add(driverData.LapNumber, currentLap);

            int lapsCount = 0, completedDriverLaps = 0, cleanLaps = 0;
            this.TotalLaps = driverData.TotalLaps;

            //if it's not the first lap
            if (driverData.TotalLaps > 0)
            {
                //previous lap
                if (this.CurrentLap == null || !this.CurrentLap.Escaped)
                {
                    this.CompletedLaps++;

                    if (this.CurrentLap == null || !this.CurrentLap.MaxIncident.HasValue)
                        this.CleanLaps++;
                }
            }

            foreach (DriverLapsInfo laps in this.Parent.LapsByVehicle.Values)
            {
                lapsCount += laps.TotalLaps;
                completedDriverLaps += laps.CompletedLaps;
                cleanLaps += laps.CleanLaps;
            }

            this.Parent.Parent.SetLapsCount(driverData, lapsCount, driverData.Class, completedDriverLaps, cleanLaps);
        }

        this.CurrentLap = currentLap;

        //add incidents
        if (driverData.Incidents != null)
        {
            foreach (IncidentScore incident in driverData.Incidents)
            {
                this.CurrentLap.MaxIncident = Math.Max(this.CurrentLap.MaxIncident ?? 0, incident.Strength);
                this.CurrentLap.Incidents++;
                this.Incidents++;
            }                
        }

        LapInfo previousLap = null;
        if ((this.PreviousLap == null || this.PreviousLap.Lap != driverData.TotalLaps) &&
            this.Laps.TryGetValue(driverData.TotalLaps, out previousLap))
        {
            this.PreviousLap = previousLap;

            if (!this.PreviousLap.Date.HasValue)
            {
                this.PreviousLap.Date = DateTime.UtcNow;
            }
        }

        if (currentLap.Position == 0)
            currentLap.Position = driverData.Position;

        if (driverData.CurrentS1 > 0)
        {                
            **if (!currentLap.S1.HasValue)**
            {
                this.UpdateBestS1(driverData.BestS1);
                this.Parent.Parent.UpdateBestS1(driverData.BestS1, driverData.UniqueName);
                currentLap.UpdateS1(driverData.CurrentS1, driverData);

                //reset the best split set at the finish line
                if (this.PreviousLap != null && this.PreviousLap.SplitBest < 0)
                    this.PreviousLap.SplitBest = 0;
            }

            if (driverData.CurrentS2.HasValue && driverData.CurrentS1.HasValue && !currentLap.S2.HasValue)
            {
                double s2 = driverData.CurrentS2.Value - driverData.CurrentS1.Value;    
                this.UpdateBestS2(s2);
                this.Parent.Parent.UpdateBestS2(s2, driverData.UniqueName);
                currentLap.UpdateS2(s2, driverData);                           
            }
        }            

        if (this.PreviousLap != null)
        {
            if (driverData.LastLap > 0)
            {
                if (!this.PreviousLap.S3.HasValue && driverData.LastS2.HasValue)
                {
                    double s3 = driverData.LastLap.Value - driverData.LastS2.Value;
                    this.UpdateBestS3(s3);
                    this.Parent.Parent.UpdateBestS3(s3, driverData.UniqueName);                        
                    this.PreviousLap.UpdateS3(s3, driverData);
                }

                if (!this.PreviousLap.LapTime.HasValue)
                {
                    double? bestLap = this.Parent.Parent.BestLap;
                    this.PreviousLap.UpdateLapTime(driverData, 0);
                    this.Parent.Parent.UpdateBestLap(this.PreviousLap, driverData.BestLap, driverData);
                    this.UpdateBestLap(driverData.BestLap, this.PreviousLap);
                    this.PreviousLap.UpdateLapTime(driverData, bestLap);
                }
            }

            else
            {
                if (this.PreviousLap.SplitBest.HasValue)
                    this.PreviousLap.UpdateBestSplit();
                if (this.PreviousLap.SplitSelf.HasValue)
                    this.PreviousLap.UpdateSelfSplit();
            }
        }

        if (driverData.InPits)
        {
            switch (driverData.Sector)
            {
                case Sectors.Sector1:
                    if (previousLap != null)
                        previousLap.InPits = true;
                    break;
                case Sectors.Sector3:
                    currentLap.InPits = true;
                    break;
            }
        }

        //lap to speed
        if (currentLap.TopSpeed < driverData.Speed)
        {
            driverData.TopSpeedLap = driverData.Speed;
            currentLap.UpdateTopSpeed(driverData.Speed);
        }
        else
            driverData.TopSpeedLap = currentLap.TopSpeed;

        //overall top speed
        if (this.TopSpeed < driverData.Speed)
        {
            driverData.TopSpeed = driverData.Speed;
            this.TopSpeed = driverData.Speed;
            this.Parent.Parent.UpdateTopSpeed(this.TopSpeed, driverData);
        }

        else
            driverData.TopSpeed = this.TopSpeed; 

    }

在地球上没有办法让代码到达那条线并且 currentLap beeing null。

还是我疯了? :)

【问题讨论】:

  • 在哪里/如何声明 _s1,您是否 - 真的,真的确定 - currentLap 不可能为空?
  • 尝试: if(currentLap != null && !currentLap.S1.HasValue) 这将首先检查 currentLap 是否为空。
  • 我强烈怀疑currentLap null。尝试创建一个简短但完整的程序来演示问题。
  • 如果currentLap 不为空,则错误发生在其他地方,或者在由于属性访问而调用的方法内部,或者在您显示的行之前/之后。
  • 在出错的那一行之前添加System.Diagnostics.Debug.Assert(currentLap != null)

标签: c# release nullable nullreferenceexception


【解决方案1】:

.HasValue 不会在可空引用为空时抛出,但如果 a 为空,a.b.HasValue 会抛出。 我怀疑currentLap == null。我知道你说你确定currentLap 不为空,但我认为这是最有可能的解释。你能发布更多代码吗?

更新:

感谢您发布代码。

这不会抛出:

void Main() {
    var f = new Foo();

    Console.WriteLine (f.S1);
    Console.WriteLine (f.S1.HasValue);
}

class Foo {
    private double? _s1 = null;

    public double? S1 {
        get { return _s1; }
        set { _s1 = value; }
    }   
}

您能尝试创建一个最小的复制品吗? (显示问题的最少代码)

【讨论】:

  • 发布了代码。即使不运行它,你也可以知道它不能为空
  • 你怎么知道它不能为空?我没看到。
【解决方案2】:

也许看看前一行代码 :) - 调试器通常会突出显示实际抛出 NullReferenceException 的行之后的下一行。

【讨论】:

  • 这完全发生在我身上。
猜你喜欢
  • 1970-01-01
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
  • 2011-08-18
  • 1970-01-01
相关资源
最近更新 更多