Handvoll Magie

Mar 8, 2010 at 10:08 PM

Die Magie ist da, in der Idee und in der verzwickt einfachen Implementierung. Wie gesagt, wenn das ganze SO nicht funktioniert ist ne Menge zu lernen wie dieser Code fließt.
Die Handvoll Strombeinchen verstehen sich auf Anhieb, wenn auch falsch. Wenn man nicht jedem seine individuelle Identität gibt. Im ersten Anlauf wollte ich genau das testen und Kurzschluss in Batterie war eigentlich klar.

Batterie sollte mit Lampe und die wieder mit Batterie. Was tat sich statt dessen ? Jeder so oft es ging mit jedem: B mit B und L mit L und B mit L, oder so:

:::Binding @ 08.03.2010 22:24:04, called by: rw.ebc.fj.stroemchen.Laempchenkreis.SwitchOn()
Out: rw.ebc.fj.stroemchen.Batteriechen.[On]Strom(rw.ebc.fj.stroemchen.Strom) -> In: rw.ebc.fj.stroemchen.Batteriechen.[Process]Strom(rw.ebc.fj.stroemchen.Strom)
Out: rw.ebc.fj.stroemchen.Batteriechen.[On]Strom(rw.ebc.fj.stroemchen.Strom) -> In: rw.ebc.fj.stroemchen.Laempchen.[Process]Strom(rw.ebc.fj.stroemchen.Strom)
Out: rw.ebc.fj.stroemchen.Laempchen.[On]Strom(rw.ebc.fj.stroemchen.Strom) -> In: rw.ebc.fj.stroemchen.Batteriechen.[Process]Strom(rw.ebc.fj.stroemchen.Strom)
Out: rw.ebc.fj.stroemchen.Laempchen.[On]Strom(rw.ebc.fj.stroemchen.Strom) -> In: rw.ebc.fj.stroemchen.Laempchen.[Process]Strom(rw.ebc.fj.stroemchen.Strom)

Wehe das zeigt jemand seinem Elektromeister !!!!!!!

Es geht los, mit 1 Strömlingen...
Batteriechen:Schicke 0,9 Strömlinge...
Batteriechen:Schicke 0,8 Strömlinge...
Batteriechen:Schicke 0,6999999 Strömlinge...
... etc...
Batteriechen:Schicke 0,09999993 Strömlinge...
Batteriechen:Schluss aus...,nix mehr da!
Lampe bleibt dunkel ohne Strom und kann auch nix weitergeben
Lampe bleibt dunkel ...
Lampe bleibt dunkel ... einige etc.

Ich hatte implizite gehofft dass die Implementierung derartiges berücksichtigt und dass Ralf an dieser Stelle etwas für mich zum Spielen gelassen hat.
Hab ich also gespielt und seinen schönen Code ein bischen verwurschtelt: dem ComponentBinder.Bind hab ich einen "bool unterscheideDieKomponenten" hinzugefügt und über "PairUpPins" durchgereicht bis zum entscheideneden "CheckIfPinsMatch" weitergereicht:

private static bool CheckIfPinsMatch(InputPin pIn, OutputPin pOut,bool distinctComponents) {
	return	(distinctComponents? pIn.ComponentType != pOut.ComponentType:true) &&
		pIn.ParameterType == pOut.ParameterType &&
		pIn.PinName == pOut.PinName;
}
Damit bekomme ich :
:::Binding @ 08.03.2010 22:24:33, called by: rw.ebc.fj.stroemchen.Laempchenkreis.SwitchOn()
Out: rw.ebc.fj.stroemchen.Batteriechen.[On]Strom(rw.ebc.fj.stroemchen.Strom)  ->  In: rw.ebc.fj.stroemchen.Laempchen.[Process]Strom(rw.ebc.fj.stroemchen.Strom)
Out: rw.ebc.fj.stroemchen.Laempchen.[On]Strom(rw.ebc.fj.stroemchen.Strom)  ->  In: rw.ebc.fj.stroemchen.Batteriechen.[Process]Strom(rw.ebc.fj.stroemchen.Strom)
Also wie mir vorschwebte Batteriechen->Laempchen->Batteriechen
Es geht los, mit 1 Strömlingen...
Batteriechen:Schicke 0,9 Strömlinge...
Lampe leuchtet mit 0,9 Strömlingen
Batteriechen:Schicke 0,6999999 Strömlinge...
Lampe leuchtet mit 0,6999999 Strömlingen
Batteriechen:Schicke 0,4999999 Strömlinge...
Lampe leuchtet mit 0,4999999 Strömlingen
Batteriechen:Schicke 0,2999999 Strömlinge...
Lampe leuchtet mit 0,2999999 Strömlingen
Batteriechen:Schicke 0,09999993 Strömlinge...
Lampe leuchtet mit 0,09999993 Strömlingen
Batteriechen:Schluss aus...,nix mehr da!

Sie haben sich in der richtigen Reihenfolge verkuppelt.

Fürs Nachbauen:

namespace rw.ebc.fj.stroemchen {
	public class Program {
		static void Main(string[] args) {
			Laempchenkreis k = new Laempchenkreis(1);
			k.SwitchOn(false );
			Console.ReadLine();
			k = new Laempchenkreis(1);
			k.SwitchOn(true);
			Console.ReadLine();
		}
	}
}

namespace rw.ebc.fj.stroemchen {
	class Batteriechen: IStromInPin,IStromOutPin {

		private Strom strom = new Strom();

		public Batteriechen(Strom strom) {
			this.strom = strom;
		}
		public Batteriechen(Single ampere) {
			this.strom.Ampere = ampere;
		}
		public void Online() {
			Console.WriteLine("Es geht los, mit {0} Strömlingen...",this.strom.Ampere);
			ProcessStrom(this.strom);
		}
		#region IStromInPin Member

		public void ProcessStrom(Strom strom) {
			this.strom.Ampere = strom.Ampere - 0.1F;
			if (this.strom.Ampere > 0F) {
				Console.WriteLine("Batteriechen:Schicke {0} Strömlinge...", this.strom.Ampere);
				OnStrom(this.strom);
			} else {
				Console.WriteLine("Batteriechen:Schluss aus...,nix mehr da!");
			}
		}

		#endregion

		#region IStromOutPin Member

		public event Action<Strom> OnStrom;

		#endregion
	}
}

namespace rw.ebc.fj.stroemchen {
	class Laempchen :IStromInPin,IStromOutPin {
		#region IStromInPin Member

		public void ProcessStrom(Strom strom) {
			if (strom.Ampere > 0) {
				Console.WriteLine("Lampe leuchtet mit {0} Strömlingen", strom.Ampere);
				strom.Ampere = strom.Ampere - 0.1F;
				OnStrom(strom);
			} else {
				Console.WriteLine("Lampe bleibt dunkel ohne Strom und kann auch nix weitergeben");
				//ist es richtig dass der verbraucher stop sagt sollte das nicht der sendeunfähige sender tu ?
				// kommt eben drauf an: hier soll der verbraucher noch seinen zustand melden
				//das geht mit ENDE-Signal also neuem Pin auch
			}
		}

		#endregion

		#region IStromOutPin Member

		public event Action<Strom> OnStrom;

		#endregion
	}
}

namespace rw.ebc.fj.stroemchen {
	class Laempchenkreis {
		private Batteriechen batterie;
		private Laempchen lampe;
		public Laempchenkreis(Single batteryAmpere) {
			batterie = new Batteriechen(batteryAmpere);
			lampe = new Laempchen();
		}
		public void SwitchOn(bool distinctComponents) {
			new ComponentBinder().Bind(new object[] { batterie , lampe },null,distinctComponents );
			batterie.Online();
		}
	}
}
Ach ja und wer ist "distinctComponents" ?´
public void Bind(object[] components, Action<object> listener,bool distinctComponents) {
	var mi = new StackTrace().GetFrame(1).GetMethod();
	File.AppendAllText(LOG_FILENAME, string.Format("\r\n:::Binding @ {0}, called by: {1}.{2}()\r\n", DateTime.Now, mi.DeclaringType.FullName, mi.Name));

	PairUpPins(components,distinctComponents)
		.ForAll(pair => {
			File.AppendAllText(LOG_FILENAME, string.Format("{0}  ->  {1}\r\n", pair.Out, pair.In));
			WireUpPins(pair, listener);
		});
}
internal static IEnumerable<OutputInputPinPair> PairUpPins(IEnumerable<object> components, bool distinctComponents) {
	var allOutputPins = from c in components
			from p in CompileEventsPublishedBy(c)
			select p;

	var allInputPins = from c in components
			from p in CompileEventHandlersPublishedBy(c)
			select p;

	foreach (var pOut in allOutputPins) {
		var matchingInputPins = from pIn in allInputPins
				where CheckIfPinsMatch(pIn, pOut,distinctComponents)
select pIn; foreach (var pInMatch in matchingInputPins) yield return new OutputInputPinPair { Out = pOut, In = pInMatch }; } }
private static bool CheckIfPinsMatch(InputPin pIn, OutputPin pOut,bool distinctComponents) {
	return	(distinctComponents? pIn.ComponentType != pOut.ComponentType:true) &&
		pIn.ParameterType == pOut.ParameterType &&
		pIn.PinName == pOut.PinName;
}
 Mit etwas mehr Reflection und organisierterem Bind läßt sich wohl noch mehr zaubern.
Üsch bün züfrüdün(sorry dear english friends: i am satisfied)
Das macht spassss und was hier Entities und Components sind ist auch nur eine Frage der Brauchbarkeit dieses Konzepts im Kontext.
Mar 16, 2010 at 10:41 AM

Hallo Frank,
ich habe mich jetzt auch schon eine ganze Weile mit EBC beschäftigt, aber den ComponentBinder erst einmal aussen vor gelassen. Der Grund ist einfach: Verbinde ich die Events von Hand, lerne ich pesönlich besser die Hintergründe. Es ist also keine Kritik am ComponentBinder.
Der Grund warum ich antworte, ist ein anderer: Ich denke man sollte EBC nicht zu sehr mit elektrischen Schaltkreisen vergleichen! Elektrische Schaltkreise haben immer eine "Rückleitung" damit der Stromkreis geschlossen wird. Das gibt es bei EBC nicht. Hier fließen die Events (quasi der Strom) nur von der Quelle zum Ziel. Ausnahmen sind Rückmelde-Events wie z.B. für eine Statusabfrage. Die lassen sich übrigens hervoragend zu einem Bus zusammenfassen (z.B. als POCO, Dictionary oder List). Den noch als eigene Komponente integriert (BusConnector), und schon kann man eine UI als Kontrolldisplay dranhängen.

Gruß
Rainer

Mar 19, 2010 at 11:07 PM

Hallo Rainer,
völlig Recht ich hab mich in Spielereien ergangen. Sach ich ma rw is Schuld mit seinem elektrischen Motivationspiel. Eine der nächsten Versionen des ComponentBinder wird mich trotzdem interessieren weil ich das händische Zusammenbasteln selber schon nervig finde und den Kollegen damit schon gleich gar nicht damit kommen mag. Ohne Definition geeigneter "Platinen" kam ich auch nicht mit weiteren Bedingungen im Binder voran. Leider gehört das ganze Thema derzeit nicht zu meinem offiziellen Spielplan und ich stelle es erstmal ein wenig zurück. Aber die Idee hat gezündet und Dein Kommentar war pädagogisch wertvoll, mein Spieltrieb eher ziellos. Bis später also...