Laden...

Ein einfacher ObjektController überwacht Referenzen

Erstellt von Programmierhans vor 18 Jahren Letzter Beitrag vor 18 Jahren 3.518 Views
Programmierhans Themenstarter:in
4.221 Beiträge seit 2005
vor 18 Jahren
Ein einfacher ObjektController überwacht Referenzen

Irgendwie hab ich heute einfach gedacht ein ObjektController könnte ev. mal nützlich sein.

Der ObjektController nimmt Referenzen auf erstellte Objekte entgegen und speichert diese intern als WeakReferences.

Wenn beim Programmende noch LivingObjects rumschwirren dann wurden diese noch nicht vom GarbageCollector (GC) entsorgt (was an und für sich nichts schlimmes ist, sofern keine RootReference mehr auf das Objekt besteht).

Im Debug-Modus wird daher vor Ermittlung "lebender" Objekte ein GC.Collect durchgeführt. In einem Release-Build wird dies nicht durchgeführt !!! Ueberhaupt macht diese Klasse nur Sinn um Programme zu debuggen..... Falls jemand die Klasse ernsthaft in einem Release-Build einsetzen will, dann rate ich dazu, die #if DEBUG Statements herauszulöschen, da ansonsten nicht die erwarteten Werte zurückgegeben werden (wie ihr ja hoffentlich alle wisst entsorgt der GC die Objekte nur bei Memory-Notstand sofort).

Man kann sich die noch "lebenden" Objekte im DebugModus ansehen (oder per MessageBox)....

Also: Wer Probleme hat wie z.B:

  • Die Anwendung wird nicht sauber beendet
  • Die Anwendung frisst unnötig Speicher bis das Swap-File voll ist
    ......

Kann diese ja mal mit diesem Controller überwachen....

Programmierhans





using System;
using System.Collections;

namespace ObjectController
{
	/// <summary>
	/// Ein einfacher Objekt - Controller
	/// Man kann ihm alles übergeben
	/// 
	/// Er hält dabei eine WeakReference auf die übergebenen Objekte
	/// 
	/// Wichtig: diese Klasse hat im DebugModus ein anderes Laufzeitverhalten !!
	/// </summary>
	public class CreatedObjects : ArrayList
	{

		public CreatedObjects()
		{
		}

		/// <summary>
		/// Fügt neue Objekte hinzu
		/// </summary>
		/// <param name="value">das neue Objekt</param>
		/// <returns>den Index</returns>
		public override int Add(object value)
		{
			return this.AddInternal(value);
		}

		/// <summary>
		/// Indexer
		/// </summary>
		public override object this[int index]
		{
			get
			{
				object o=base[index];
				if (o!=null)
				{
					WeakReference wr=o as WeakReference;
					if (wr!=null && wr.IsAlive)
					{
						return wr.Target;
					}
				}
				return null;
			}
			set
			{
				this.SetInternal(index,value);
			}
		}

		/// <summary>
		/// Erstellt eine WeakRef und legt diese in der ArrayList ab
		/// </summary>
		/// <param name="value">das objekt</param>
		/// <returns>der vergebene Index</returns>
		private int AddInternal(object value)
		{
			if (value!=null)
			{
				return base.Add (this.CreateWeakRefInternal(value));
			}
			return -1;

		}

		/// <summary>
		/// Legt eine WeakReference an und setzt diese am entsprechenden Ort innerhalb der ArrayList
		/// </summary>
		/// <param name="index">der Index des zu setzenden Wertes</param>
		/// <param name="value">der Wert</param>
		private void SetInternal(int index,object value)
		{
			base[index]=this.CreateWeakRefInternal(value);
		}

		/// <summary>
		/// Erstellt eine WeakReference
		/// </summary>
		/// <param name="value">das Objekt</param>
		/// <returns>die WeakReference</returns>
		private WeakReference CreateWeakRefInternal(object value)
		{
			return new WeakReference(value,false);
		}

		//und so weiter für alle Member die man verwenden will


		/// <summary>
		/// Liefert die Anzahl der noch "lebenden" Objekte
		/// Wichtig: dieses Property hat im DebugModus ein anderes Laufzeitverhalten !!
		/// </summary>
		public int LivingObjectsCount
		{
			get
			{
				int ret=0;
#if DEBUG
				GC.Collect();
#endif
				foreach (WeakReference wr in this)
				{
					if (wr!=null && wr.IsAlive)
					{
						ret++;
					}
				}
				return 0;
			}
		}

		/// <summary>
		/// Liefert eine ArrayList welche nur noch die "lebenden" Objekte enthält
		/// WICHTIG: Solange die zurückgegebene ArrayList "lebt" wird kein einziges vom GarbageCollector entsorgt,
		/// weil dann ja eine normale Referenz auf die internen Objekte besteht !!!
		/// Wichtig: dieses Property hat im DebugModus ein anderes Laufzeitverhalten !!
		/// </summary>
		/// <returns>die ArrayList</returns>
		public ArrayList GetLivingObjects()
		{
			ArrayList ret=new ArrayList();
#if DEBUG
			GC.Collect();
#endif
			for (int i=0;i<this.Count;i++)
			{
				WeakReference wr=base[i] as WeakReference;
				if (wr!=null && wr.IsAlive)
				{
					ret.Add(wr.Target);
				}
			}
			return ret;
		}
	}
}


Aufrufender Code:




		CreatedObjects _Objects=new CreatedObjects();
		private void button1_Click(object sender, System.EventArgs e)
		{
			for (int i=0;i<10;i++)
			{
				Form f=new Form();
				this._Objects.Add(f);
				f.Text=i.ToString();
				f.Show();
			}
		}

		private void button2_Click(object sender, System.EventArgs e)
		{
			ArrayList arr=this._Objects.GetLivingObjects();
			StringBuilder sb=new StringBuilder();
			foreach (object o in arr)
			{
				if (o!=null)
				{
					sb.Append(o.ToString());
					sb.Append(Environment.NewLine);
				}
			}
			MessageBox.Show(sb.ToString());
		}



Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...