У меня есть библиотека классов с кучей статических методов. При попытке вызвать один из них я обнаружил необработанное исключение 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;
}