Необычное исключение StackOverflowException в ListDictionaryInternal - PullRequest
0 голосов
/ 10 ноября 2019

У меня есть библиотека классов с кучей статических методов. При попытке вызвать один из них я обнаружил необработанное исключение StackOverflowException где-то в классе ListDictionaryInternal.

Я попытался включить пошаговое выполнение .Net Framework (v 4.5.2), окружить вызов блоком try / catch и выполнить его шагшаг за шагом Когда я помещаю оператор continue после комментария в Приложении A, затем комментирую его во время отладки, метод работает как положено. В противном случае я даже не могу достичь точки останова в начале метода. Я также попытался вызвать метод со всеми параметрами, установленными в нуль, но это также не помогло.

public static List<CalcSector> Split(List<CalcSector> calibration, List<ProfilePoint> profile, List<MeasurementPoint> additionalPoints)
{
    double lengthCorridor = 10d;
    double lengthEpsilon = 1d;
    if (!(calibration?.Any() ?? false)) throw new ArgumentNullException(nameof(calibration), "Empty calibration table");
    if (!(profile?.Any() ?? false)) throw new ArgumentNullException(nameof(profile), "Empty profile points collection");
    for (int i = 0; i < calibration.Count - 1; i++)
        if (Math.Abs(calibration[i].EndDistance - calibration[i + 1].StartDistance) > lengthEpsilon)
            throw new ArgumentException($"calibration[{i}]", "Calibration table integrity is compromised");
    List<CalcSector> result = new List<CalcSector>();
    List<ProfilePoint> SummitPoints = new List<ProfilePoint>();
    calibration.ForEach(x => result.Add(x));
    profiles = profile.OrderBy(x => x.Distance).ToList();
    //
    if (additionalPoints?.Any() ?? false)
        foreach (MeasurementPoint mp in additionalPoints.Where(x => x.Id != int.MinValue && x.Id != int.MaxValue))
            for (int i = 0; i < result.Count; i++)
                if (Math.Abs(mp.Distance - result[i].StartDistance) > lengthEpsilon && Math.Abs(mp.Distance - result[i].EndDistance) > lengthEpsilon && mp.Distance > result[i].StartDistance && mp.Distance < result[i].EndDistance)
                {
                    CalcSector c = new CalcSector()
                    {
                        StartDistance = mp.Distance,
                        StartHeight = BinaryHeightSearch(mp.Distance),
                        StartPointId = mp.Id,
                        EndDistance = result[i].EndDistance,
                        EndHeight = result[i].EndHeight,
                        Length = result[i].EndDistance - mp.Distance,
                        Thickness = result[i].Thickness,
                    };
                    result[i].EndDistance = mp.Distance;
                    result[i].EndHeight = c.StartHeight;
                    result[i].EndPointId = mp.Id;
                    c.Volume = result[i].Volume / result[i].Length * c.Length;
                    result[i].Length -= c.Length;
                    result[i].Volume -= c.Volume;
                    result.Insert(i + 1, c);
                    break;
                }
                else if (Math.Abs(mp.Distance - result[i].StartDistance) < lengthEpsilon)
                    result[i].StartPointId = mp.Id;
                else if (Math.Abs(mp.Distance - result[i].EndDistance) < lengthEpsilon)
                    result[i].EndPointId = mp.Id;
    int start = 0;
    int end = 0;
    bool hasSpikes = true;
    while (hasSpikes)
    {
        hasSpikes = false;
        //Appendix A
        for (int j = 0; j < result.Count; j++)
        {
            result[j].z = -1d * (result[j].StartHeight - result[j].EndHeight) / (result[j].EndDistance - result[j].StartDistance);
            result[j].sI = start = BinaryProfileSearch(result[j].StartDistance);
            result[j].eI = end = BinaryProfileSearch(result[j].EndDistance);
            for (int i = start + 1; i < end; i++)
                if (Math.Abs(result[j].z * (profiles[i].Distance - result[j].StartDistance) + result[j].StartHeight - profiles[i].Height) > lengthCorridor)
                {
                    int maxIndex = -1;
                    double maxH = double.MinValue;
                    int minIndex = -1;
                    double minH = double.MaxValue;
                    for (; start < end; start++)
                    {
                        if (Math.Abs(result[j].z * (profiles[start].Distance - result[j].StartDistance) + result[j].StartHeight - profiles[start].Height) <= lengthCorridor)
                            continue;
                        if (result[j].z * (profiles[i].Distance - result[j].StartDistance) + result[j].StartHeight - profiles[i].Height > maxH)
                        {
                            maxH = profiles[start].Height;
                            maxIndex = start;
                        }
                        if (result[j].z * (profiles[i].Distance - result[j].StartDistance) + result[j].StartHeight - profiles[i].Height < minH)
                        {
                            minH = profiles[start].Height;
                            minIndex = start;
                        }
                    }
                    int target = Math.Min(maxIndex, minIndex);
                    CalcSector c = new CalcSector()
                    {
                        StartDistance = profiles[target].Distance,
                        StartHeight = profiles[target].Height,
                        sI = target,
                        EndDistance = result[j].EndDistance,
                        EndHeight = result[j].EndHeight,
                        EndPointId = result[j].EndPointId,
                        eI = result[j].eI,
                        Length = result[j].EndDistance - profiles[target].Distance,
                        Thickness = result[j].Thickness,
                    };
                    result[j].EndDistance = c.StartDistance;
                    result[j].EndHeight = c.StartHeight;
                    result[j].EndPointId = null;
                    result[j].eI = target;
                    result[j].z = -1d * (result[j].StartHeight - result[j].EndHeight) / (result[j].EndDistance - result[j].StartDistance);
                    c.Volume = result[j].Volume / result[j].Length * c.Length;
                    result[j].Length -= c.Length;
                    result[j].Volume -= c.Volume;
                    result.Insert(j + 1, c);
                    hasSpikes = true;
                    break;
                }
        }
    }
    for (int j = 0; j < result.Count; j++)
    {
        result[j].Diameter = 1000d * Math.Sqrt(4d * result[j].Volume / Constants["PI"] / result[j].Length);
        result[j].OrdNum = j;
    }
    result.First().StartPointId = int.MinValue;
    result.Last().EndPointId = int.MaxValue;

    for (int i = 1; i < profiles.Count - 1; i++)
        if (profiles[i - 1].Height < profiles[i].Height && profiles[i].Height > profiles[i + 1].Height)
            SummitPoints.Add(profiles[i]);
    return result;
}

public class CalcSector
{
    public int OrdNum;
    public double StartDistance;
    public double StartHeight;
    public int? StartPointId;
    public double EndDistance;
    public double EndHeight;
    public int? EndPointId;
    public double Length;
    public double Volume;
    public double Diameter;
    public double Thickness;
    public int sI;
    public int eI;
    public double z;
}
public class ProfilePoint
{
    public double Distance;
    public double Height;
}
public class MeasurementPoint
{
    public int Id;
    public double Distance;
}

Я ожидаю, что этот метод разделит некоторые из исходных CalcSectors на меньшие, но всеесть это необработанное роковое исключение.

Добавлено:

private static int BinaryProfileSearch(double distance)
{
    if (profiles == null || profiles.Count == 0)
        return -1;
    //assuming that profile points are already ordered by distance
    if (distance <= profiles.First().Distance)
        return 0;
    if (distance >= profiles.Last().Distance)
        return profiles.Count - 1;
    int first = 0;
    int last = profiles.Count - 1;
    while (first + 1 < last)
    {
        int mid = (first + last) / 2;

        if (distance <= profiles[mid].Distance)
            last = mid;
        else
            first = mid + 1;
    }
    if (distance - profiles[first].Distance > profiles[last].Distance - distance)
        return last;
    else
        return first;
}

1 Ответ

0 голосов
/ 11 ноября 2019

Решение пришло довольно неожиданно: недопустимое значение контрольного слова 8087. Следующая строка меняет его обратно.

_controlfp(0x9001F, 0xFFFFF);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...