Entwickler-Ecke
WinForms - NullReferenceException obwohl Objekt vorhanden List<float[]>
C# - Do 26.12.13 23:28
Titel: NullReferenceException obwohl Objekt vorhanden List<float[]>
Hey,
ich habe ma wieder ein Problem und zwar arbeite ich (wie schon in einigen Threads erwähnt :D) an einem SpectrumAnalyzer. Bis jetzt klappt alles relativ gut.
Die Daten verwerten klappt gut aber ich habe mit dem Anzeigen (Balkendiagramm) ein kleines Problem. Ich puffere die Audiodaten noch zusätzlich nach Zeit um einen glatteren Lauf der Balken zu erreichen. Wenn ich den Puffer einschalte (z.B. 0.1s) klappt dass auch soweit. Nach einiger Zeit (ca. 10s-20s) bekomm ich auf einmal eine Fehlermeldung aus heiterem Himmel in der markierten Zeile.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| private void UpdateTimeBuffer() {
while (spectrumBufferTimes.Count > 0 && spectrumBufferTimes[0] + TimeBuffer < Environment.TickCount) { spectrumBufferTimes.RemoveAt(0); spectrumBuffer.RemoveAt(0); }
if (spectrumBuffer.Count <= 0) { CalculateBars(new float[BarsCount]); return; }
float[] f = new float[spectrumBuffer[0].Length];
ActualBufferSize = f.Length * 4 * spectrumBuffer.Capacity;
for (int i = 0; i < f.Length * spectrumBuffer.Count; i++) f[i / spectrumBuffer.Count] += spectrumBuffer[i % spectrumBuffer.Count][i / spectrumBuffer.Count] / spectrumBuffer.Count; CalculateBars(f); } |
Quelltext
1: 2: 3: 4: 5:
| NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt. System.NullReferenceException was unhandled HResult=-2147467261 Message=Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt. Source=MovTest |
Alle Arrays haben absolut gültige Werte und ich bin auch nirgends außerhalb des Index...
Kennt jemand das Problem oder weiß woher es kommt??? Ich hab absolut keinen Schimmer...
Ralf Jansen - Fr 27.12.13 01:16
Zitat: |
Alle Arrays haben absolut gültige Werte und ich bin auch nirgends außerhalb des Index... |
Dann würdest du offensichtlich nicht diese Exception bekommen. In erster Instanz solltest du der Runtime trauen und nicht dir ;)
Da du eine NullReferenceException und keine IndexOutOfRangeException bekommst bist du zumindest nicht außerhalb des Arraybereichs bleibt das der Inhalt eines deiner Array Zellen leer ist.
Hast du das überprüft? spectrumBuffer scheint ja ein jagged Array zu sein hast du denn die zweite Dimension initialisiert?
C# - Fr 27.12.13 17:01
Ja die Runtime weiß besser als ich bescheid ich weiß :D
Ich finds nur komisch, dass wenn die Exception geworfen wird und ich bei dem aktuellen Index nachsehe ein Wert vorhanden ist.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| public void AddValues(float[] spectrum) { if (TimeBuffer <= 0) CalculateBars(spectrum); else if (spectrum.Max() > 0.05f) { spectrumBuffer.Add(spectrum); spectrumBufferTimes.Add(Environment.TickCount); } } |
Anmerkung
Habe jetzt bei der oben erwähnet Funktion noch ne Prüfung auf
float.IsInfinity() und
float.IsNaN() gemacht. Dabei registrier ich ca. 1 ungültiges float-Array pro Sekunde (infinity), welches ich dann aber nicht zum spectrumBuffer hinzufüge. Jedoch erhalte ich trotzdem noch den Fehler mit der gleichen Wiederholfrequenz... Wenn ich die Exception abfange und in den Output schreibe, erhalte ich sie genau 1 mal ca. alle 10-20sec.
Ich bin verwirrt
Th69 - Fr 27.12.13 21:12
Hallo C#,
arbeitest du mit verschiedenen Threads?
C# - Sa 28.12.13 20:44
Jaein. Ich benutze 2 DispatcherTimer. Einer für's Rendering mit 20ms / 25Hz und einer für die Pufferung mit 10ms / 100Hz. Durch Verwendung des Dispatchers bleibe ich doch auf dem UI Thread, bin also synchron, oder? Ich habs Versuchshlber mal mit
lock probiert, gleiches Ergebnis...
Hier mal der komplette Code der Datei
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Runtime.Remoting.Contexts; using System.Threading; using System.Windows; using System.Windows.Forms; using System.Windows.Threading;
namespace MovTest.UI { public class AudioGraph : Control { public Brush Background { get; set; }
public Color MaximumValueColor { get { return _maximumValueColor; } set { foreground = new LinearGradientBrush(DisplayRectangle, value, BarColor, LinearGradientMode.Vertical); _maximumValueColor = value; } }
public Color BarColor { get { return _barColor; } set { foreground = new LinearGradientBrush(DisplayRectangle, MaximumValueColor, value, LinearGradientMode.Vertical); _barColor = value; } }
public int ActualBufferSize { get; private set; }
[DefaultValue(16)] public int BarsCount { get { return _barsCount; } set { _barsCount = value; UpdateValues(); InitTimeBuffer(); } }
[DefaultValue(4.0f)] public float Space { get { return _space; } set { _space = value; UpdateValues(); } }
[DefaultValue(1.0f)] public float VerticalScale { get; set; }
[DefaultValue(0)] public int TimeBuffer { get { return _timeBuffer; } set { if (value < 0 || value > 3000) return; _timeBuffer = value; InitTimeBuffer(); } }
private Color _maximumValueColor, _barColor; private int _timeBuffer; private int _barsCount; private float _space;
private float barWidth; private RectangleF[] bars; private Brush foreground; private List<float[]> spectrumBuffer; private List<int> spectrumBufferTimes;
private BufferedGraphicsContext graphicsContext; private BufferedGraphics graphics; private Graphics g;
private DispatcherTimer guiTrigger, bufferTrigger;
public AudioGraph() { guiTrigger = new DispatcherTimer(new TimeSpan(0, 0, 0, 0, 40), DispatcherPriority.Render, TriggerCallback, Dispatcher.CurrentDispatcher); bufferTrigger = new DispatcherTimer(new TimeSpan(0, 0, 0, 0, 10), DispatcherPriority.Normal, BufferTriggerCallback, Dispatcher.CurrentDispatcher);
VerticalScale = 1.0f; Space = 4.0f; BarsCount = 16; TimeBuffer = 0;
Width = 20; Height = 20;
BarColor = Color.Orange; MaximumValueColor = Color.Red; Background = new SolidBrush(DefaultBackColor); UpdateValues(); InitTimeBuffer(); }
~AudioGraph() { guiTrigger.Stop(); bufferTrigger.Stop(); guiTrigger = null; bufferTrigger = null; }
public void AddValues(float[] spectrum) { if (TimeBuffer <= 0) CalculateBars(spectrum); else { spectrumBuffer.Add(spectrum); spectrumBufferTimes.Add(Environment.TickCount); } }
private void InitTimeBuffer() { if (spectrumBuffer != null) { spectrumBuffer.Clear(); spectrumBufferTimes.Clear(); }
spectrumBuffer = new List<float[]>(); spectrumBufferTimes = new List<int>();
if (TimeBuffer == 0 && bufferTrigger.IsEnabled) bufferTrigger.Stop(); else if (!bufferTrigger.IsEnabled) bufferTrigger.Start(); }
private void InitBuffering() { if (Width == 0 || Height == 0) return;
guiTrigger.Stop();
if (graphics != null) { g.Dispose(); graphics.Dispose(); }
g = CreateGraphics(); graphicsContext = BufferedGraphicsManager.Current; graphicsContext.MaximumBuffer = new System.Drawing.Size(Width + 1, Height + 1); graphics = graphicsContext.Allocate(g, DisplayRectangle);
guiTrigger.Start(); }
private void TriggerCallback(object sender, EventArgs e) { OnPaint(new PaintEventArgs(g, DisplayRectangle)); }
private void BufferTriggerCallback(object sender, EventArgs e) { if (spectrumBuffer.Count > 0) UpdateTimeBuffer(); }
private void UpdateTimeBuffer() {
while (spectrumBufferTimes.Count > 0 && spectrumBufferTimes[0] + TimeBuffer < Environment.TickCount) { spectrumBufferTimes.RemoveAt(0); spectrumBuffer.RemoveAt(0); }
if (spectrumBuffer.Count <= 0) { CalculateBars(new float[BarsCount]); return; }
float[] f = new float[BarsCount];
ActualBufferSize = f.Length * 4 * spectrumBuffer.Capacity;
try { for (int i = 0; i < f.Length * spectrumBuffer.Count; i++) f[i / spectrumBuffer.Count] += spectrumBuffer[i % spectrumBuffer.Count][i / spectrumBuffer.Count] / spectrumBuffer.Count; } catch { Debug.WriteLine("Bars: {0}, Time: {1}, Length: {2}", BarsCount,TimeBuffer, spectrumBuffer.Count); }
CalculateBars(f); }
private void CalculateBars(float[] spectrum) { if (Width == 0 || Height == 0) return;
for (int i = 0; i < spectrum.Length; i++) { float height = Height * VerticalScale * spectrum[i]; bars[i] = new RectangleF((barWidth + Space) * i, Height - height, barWidth, height); }
}
private void UpdateValues() { if (Width == 0 || Height == 0) return;
barWidth = (Width - (BarsCount - 1) * Space) / BarsCount; bars = new RectangleF[BarsCount]; InitBuffering(); foreground = new LinearGradientBrush(DisplayRectangle, MaximumValueColor, BarColor, LinearGradientMode.Vertical); }
protected override void OnResize(EventArgs e) { base.OnResize(e); UpdateValues(); }
protected override void OnPaint(PaintEventArgs e) { if (Width == 0 || Height == 0 || IsDisposed) return;
lock (this) { graphics.Graphics.Clear(BackColor); graphics.Graphics.FillRectangle(Background, DisplayRectangle); graphics.Graphics.FillRectangles(foreground, bars); graphics.Render(); } } } } |
C# - So 29.12.13 15:13
Danke erstmal für den Tipp. Ich habe jetzt den DispatcherTimer ersetzt und bei OnPaint e.Graphics verwendet.
Wenn ich SetStyle(ControlStyles.OptimizedDoubleBuffer, true) verwende, habe ich ein viel stärkeres Bildflimmern als wenn ich manual buffering verwende...
Mein Problem mit der NullReferenceException nicht zu vergessen...
Th69 - So 29.12.13 15:39
Hallo,
ich hatte gehofft, daß die
NullReferenceException verschwindet bei Verwendung des WinForm-Timers. Aber schau mal, wenn die Exception geworfen wurde, im VS unter "Threads" nach, ob nicht doch ein anderer Thread dafür verantwortlich ist.
Und du bist dir sicher, daß die Berechnungsformel bei dir so stimmt (also du die richtigen Indizes verwendet etc.)? Evtl. einfach mal in mehrere Zeilen aufteilen, um dem Fehler auf die Spur zu kommen.
Und bzgl. Flackern schau mal unter
[Artikel] Flackernde Controls und flackerndes Zeichnen vermeiden [
http://www.mycsharp.de/wbb2/thread.php?threadid=59978] nach, dort sind noch ein paar andere Flags aufgelistet.
Ralf Jansen - So 29.12.13 15:47
Habe deinen Control mal auf eine Form geworfen und mit Zufallswerten befüllt. Da knallt nix ;)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| private static Random rnd = new Random(DateTime.Now.Millisecond); private void button1_Click(object sender, EventArgs e) { while(true) { float[] f = new float[rnd.Next(1,audioGraph1.BarsCount)]; for (int i = 0; i < f.Length; i++) f[i] = (float)rnd.NextDouble(); audioGraph1.AddValues(f); Application.DoEvents(); } } |
Edit : Ich korrigiere es gibt eine IndexOutOfRangeException wenn die Länge der Spektren kleiner BarsCount ist. Das solltest du explizit abfangen. Weiterhin keine NullReferenceException.
C# - So 29.12.13 16:12
Och mann was soll n des jetzt xD
Ja das mit den BarsCount und Pufferlänge ist mir bekannt. Ist ja noch keine final version ;). Ich prüfe das momentan noch außerhalb, sodass keine falschen Werte übertragen werden.
Also der Thread der auslöst ist der MainThread. Bei der Exception überprüfe ich die Werte in den Arrays da ist alles ok damit... Und ein Berechnungsfehler kanns eigentlich auch nicht sein, da das ganze ja in 99,9% der Fälle funktioniert. Ich habe ja geschätzt 2000 Arrays pro Sekunde durch den spectrumBuffer laufen und die Ausnahme tritt ja erst nach ca 10 Sekunden auf...
Das mit dem Flickering schau ich mir noch genauer an.
Palladin007 - So 29.12.13 19:22
Nur so ein ganz spontaner Gedanke, aber ich hab in meiner Anfangszeit in der Programmier-Welt viel mit Batch rum gebastelt und bei einem kleinen "Projekt" fest gestellt, dass sich bei Rechenaufwendigen Aufgaben selten auch mal ein Fehler einschleicht.
Ich hab damals auf einem anderen Forum gefragt und wir haben alle gemeinsam den Code doppelt und dreifach durchforstet nur um fest zu stellen, dass es keinen Fehler gibt. Irgendwann meinte dann einer, dass eventuell bei sehr aufwendigen Aufgaben auch mal ein Fehler in der Berechnung passieren kann, was dann nichts mit dem Code zu tun hat.
Ich komme gerade darauf, weil du hier irgendwas schreibst, das mir sehr nach mathematisch aufwendigen Berechnungen klingt und du sagst, rund 2000 Arrays ...
Eventuell ist das ja gar nicht dein Problem, sondern du überforderst irgendwas dazwischen, dass da ein fehler passiert.
Du kannst ja mal probieren, zwischen jedem Array weniger Millisekunden zu warten. Nicht zu viel, sonst fällt das in der Gesamt-Dauer zu deutlich auf.
Ob das funktioniert kann ich dir nicht sagen, es war nur eine spontane Idee. ^^
PS:
Zitat: |
Ja das mit den BarsCount und Pufferlänge ist mir bekannt. Ist ja noch keine final version |
Bitte mach das nicht ^^
Ich persönlich versuche immer darauf zu achten, mögliche Exceptions so früh wie möglich abzufangen oder zumindest dick und fett im Code zu markieren, damit ich das nicht vergesse.
Hatte nämlich schon manchmal den Fall, dass ich genauso gedacht habe, wie du jetzt und es dann vergessen habe. Das Suchen nach dem Fehler hat am Ende dann länger gedauert als das vorherige Abfangen. ^^
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!