Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von dechavue
Thema: Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Am im Forum: Smalltalk

Dann hier noch wie versprochen die Lösung ohne zusätzliche Variable:


public static void Loop(int min, int max, Action<int> action)
{
    if (min > max)
        throw new ArgumentException("min must be lesser than or equal max");

    checked
    {
        for (int i = min; i ≤ max; max = (i == int.MaxValue ? max-1 : max), i = (i == int.MaxValue ? i : i+1))
            action(i);
    }
}

Beim oberen Grenzfall wird einfach max dekrementiert anstatt i zu inkrementieren, damit kann die Bedingung
i ≤ max ausgewertet werden ohne Überläufe zu verursachen.

Noch kürzer ginge es so:
for (int i = min; i ≤ max; min=(i == int.MaxValue ? max-- : i++)), aber da braucht man doch wieder (in diesem Fall min) als dummy-Variable, da C# hier nur assignment, call, increment, decrement zulässt.

Christian


Edit:
Danke an Herbivore, der die letzte Variante noch optimiert hat:
Zitat

for (int i = min; i ≤ max; i=(i == int.MaxValue ? max-- : i+1))

oder vielleicht noch besser so, damit der Normalfall vorne steht:

for (int i = min; i ≤ max; i=(i < int.MaxValue ? i+1 : max--))

Durch das Postdecrement von max wird im Fall i == int.MaxValue an i wieder int.MaxValue zugewiesen - i behält also bei der letzten Reinitialisierung wie gewünscht seinen (maximalen) Wert -, weil der Fall i == int.MaxValue nur eintreten kann, wenn max (ursprünglich) int.MaxValue ist.

Wenn du magst, kannst du deinen Beitrag editieren und diese Variante(n) der Vollständigkeit halber mit aufnehmen. Ich selbst werde keine Antwort schreiben, da ja schon die neue Aufgabe da ist.

Die folgende auch denkbare Variante würde ich dagegen nicht verwenden, da Inkrementoperator und Zuweisung hier doppeltgemoppelt wären:

for (int i = min; i ≤ max; i=(i < int.MaxValue ? ++i : max--))

Thema: Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Am im Forum: Smalltalk

Hallo,

es gibt auch eine einfache Variante, die ohne zusätzliche Variable auskommt & bei den Grenzfällen funktioniert.

Mangels einer Idee zu einer Aufgabe werde ich diese aber erst nach der Lösung posten

Christian

Thema: Screenshooter V2
Am im Forum: Projekte

Hallo,

Die Links sind gefixt.
Das Verdunkeln ist im wesentlichen eine Fullscreen-Tompmost Form mit einem (abgedunkeltem) Screenshot als Hintergrundbild.
Für eine Neuentwicklung würde ich hinsichtlich Performance gefühlt jedoch eher zu WPF mit echter Transparenz greifen.

Thema: Screenshooter V2
Am im Forum: Projekte

Hallo,

Danke für das feedback.

- Das mit den Hilfetexten werde ich auf jeden Fall in der nächten Version einbauen.
- Dass das Abdunkeln so langsam läuft, ist hauptsächlich ein Performanceproblem (siehe Post von Matrix-NTN).
Das ganze wird somit auf eine Neuimplementierung in WPF hinauslaufen. (Was hoffentlich gerade hinsichtlich der halbtransparenten Overlays eine Performanceverbesserung bringt)

Das mit der Gesamtansicht der Hotkey-Kombinationen ist auch eine sehr gute Idee und für die nächste Version vorgemerkt.

Momentan liegt das Projekt noch auf Eis. Ich bin gerade dabei mir anhand einiger anderer Projekte WPF ordentlich beizubringen.
Danach werde ich mich aber definitiv wieder dem Screenshooter widmen.

[offtopic]Der erste Teil ist mal abgeschlossen. Seit diesem Herbst bin ich nun im Master-Studium[/offtopic]

Thema: VS: Einstellungen für "Quellcode-Formatierung" ändern
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hallo,

Schau mal unter "Tools->Options->Text Editor->C#->Formatting" (bzw. deutsches Equivalent)
Dort kannst du unter anderem das Verhalten hinsichtlich Einrückungen, Zeilenumbrüchen oder Leerzeichen festlegen.

Thema: Suche Tool: Loadbalancing auf Applikationsebene?
Am im Forum: Smalltalk

Hi,

Eventuell könnte Netlimiter was für dich sein: http://www.netlimiter.com

Thema: Eure iPhone-Lieblings-Apps?
Am im Forum: Smalltalk

Hier meine Favoriten

Spiele:
- Expert Sudoku
- Tap Tap Revenge 3
- Avatar

AppStore Programme:
- TeamViewer
- RedLaser
- Vlc Remote

JB Programme:
- SBSettings
- iFile
- Firewall iP

Thema: Suche Programm für Datensynchronisierung zwischen zwei PCs
Am im Forum: Smalltalk

[offtopic]

Zitat von m0rius
deshalb musste meine Spam-EMail-Adresse dafür herhalten :).

Für solche Registrierungen verwende ich immer gerne http://10minutemail.com . Damit habe ich jedes mal eine andere Email-Addresse, wo ich mir auch um Spam keine Sorgen machen muss, da es sie nur 10 Minuten gibt. [/offtopic]

Thema: Kann hier ein Deadlock entstehen?
Am im Forum: Rund um die Programmierung

Schau mal unter [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke), dort ist das mit Invoke & BeginInvoke schön beschrieben, auch warum es bei Invoke zu einem Deadlock kommen kann.

Der Hauptunterschied ist, dass Invoke warted bist die Aktion im Gui-Thread abgeschlossen ist, und BeginInvoke dem Gui-Thread quasi sagt, mach mal die Aktion wenn du Zeit hast, und sofort weitermacht, ohne auf die Abarbeitung zu warten.

Thema: Kann hier ein Deadlock entstehen?
Am im Forum: Rund um die Programmierung

versuch mal statt Invoke mit BeginInvoke zu synchronisieren, da dies den aufrufenden Thread nicht blockiert.

Ich bin mir jetzt allerdings nicht 100%ig sicher, ob dies nicht wieder zu anderen Threadingprobs. durch das Schließen der Form kommen kann, da noch ein Update nach dem Schließen kommen kann.

Thema: Kann hier ein Deadlock entstehen?
Am im Forum: Rund um die Programmierung

Hallo,

Kann es sein, dass du in der Update - Funktion der Form ein Invoke verwendest um dich dort mit dem GUI-Thread zu Synchronisieren?

Wenn ja, kann folgendes Szenario entstehen:

Thread A ... Gui - Thread.
Thread B ... Thread der Fire Updates aufruft.

  • B ruft Fire Updates auf
  • Irgendwann zwischen lock (Zeile 21) und Aufruf der Update - Funktion passiert ein Threadwechsel
  • Form soll geschlossen werden und Thread A ruft Detach auf (kommt bis zu lock (Z.11) und wartet ab hier)
  • Update wird aufgerufen (Thread B).
  • Mit Invoke synchronisierung auf Thread A
  • Thread A warted auf freigabe des lock, Thread B warted auf beendigung von Invoke. A wartet auf B und B wartet auf A --> Deadlock

greets

Thema: Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Am im Forum: Smalltalk

Deine Implementierung scheint Probleme zu haben wenn gleiche Werte vorkommen.

Da ich dann weg muss und heute nicht mehr dazukomme mir eine Alternativlösung anzuschauen, lass ichs mal durchgehen.

Dann stell deine Aufgabe

Thema: Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Am im Forum: Smalltalk

Gut, dann bleiben wir gleich bei Iterativen Varianten.
Ich hätte gerne eine iterative Implementierung des Quicksort

Zu meiner Lösung:
Ich am iPhone ein TvH Spiel, bei dem die Scheiben immer abwechseld gefärbt sind.
Mir ist dann mal aufgefallen, dass beim optimalen Lösen niemals 2 gleichfarbige Scheiben aufeinanderliegen.
Daraus, und aus der Start-Bedingung, dass bei einer geraden Stapelhöhe zuerst auf das "Nicht-Zielfeld" gelegt werden muss und bei einer Ungeraden Stapelhöhe der erste Zug auf das Zielfeld erfolgen muss, ergibt sich der Ablauf von selbst:
Das nächste Ziel ist immer der Stein, mit einer anderen Farbe, bei dem die Breite größer ist, oder ein leeres Feld.
Wichtig ist noch, dass wenn beide Ziele möglich wären, das nicht leere Feld bevorzugt wird.
Die Quelle ergibt sich daraus, dass der zuletzt umgelegte Stein nicht bewegt werden darf + welcher andere Stein umgelegt werden kann.
Die abwechselnden Farben repräsentieren bei mir die Scheibenbreite % 2

Ich habe noch einen Ablauf eines 3er und 4er turms in den Anhang gegeben, zum besseren Verständnis des "Farb - Systems"


Nachtrag: Ich sehe gerade, bei meinem algo könnte man den ersten Zweig des ifs ( if (sticks[(i + 1) % sticks.Length].Count == 0 && sticks[(i + 2) % sticks.Length].Count == 0) {) komplett aus den Schleifen herausziehen, da es nur beim ersten Durchlauf true sein kann. Dann wäre der Algo eventuell auch etwas verständlicher.

Thema: Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Am im Forum: Smalltalk

Ich hatte es sinngemäs so verstanden: Keine Stacks um die Rekursive Variante iterativ zu implementieren.

Aber gut, dann hier das ganze mit Listen


        static void Main(string[] args) {
            for (int i = 1; i < 7; i++) {
                Console.WriteLine("== {0} =============================", i);
                Move(i);
            }
        }

        static void Move(int n) {
            List<int>[] sticks = new List<int>[3];

            for (int i = 0; i < sticks.Length; i++) {
                sticks[i] = new List<int>();
            }
            //Fill Stick 1
            for (int i = n; i > 0; i--) {
                sticks[0].Add(i);
            }


            int lastTargetStick = -1;


            while (sticks[0].Count > 0 || sticks[1].Count > 0) {
                for (int i = 0; i < sticks.Length; i++) {
                    if (lastTargetStick != i && sticks[i].Count > 0) {
                        if (sticks[(i + 1) % sticks.Length].Count == 0 && sticks[(i + 2) % sticks.Length].Count == 0) {
                            if (sticks[i].Count % 2 == 0) {
                                lastTargetStick = (i + 1) % sticks.Length;
                            } else {
                                lastTargetStick = (i + 2) % sticks.Length;
                            }
                            Console.WriteLine("Nr. {0} von {1} nach {2}", sticks[i][sticks[i].Count-1], i + 1, lastTargetStick + 1);
                            sticks[lastTargetStick].Add(sticks[i][sticks[i].Count-1]);
                            sticks[i].RemoveAt(sticks[i].Count - 1);
                            break;
                        } else {
                            if (sticks[(i + 1) % sticks.Length].Count > 0 && sticks[i][sticks[i].Count - 1] > sticks[(i + 1) % sticks.Length][sticks[(i + 1) % sticks.Length].Count -1] &&
                                sticks[(i + 2) % sticks.Length].Count > 0 && sticks[i][sticks[i].Count - 1] > sticks[(i + 2) % sticks.Length][sticks[(i + 2) % sticks.Length].Count - 1]) {
                                continue;
                            }
                            if ((sticks[(i + 1) % sticks.Length].Count == 0 || sticks[i][sticks[i].Count - 1] < sticks[(i + 1) % sticks.Length][sticks[(i + 1) % sticks.Length].Count - 1]) &&
                                (sticks[(i + 1) % sticks.Length].Count > 0 && sticks[i][sticks[i].Count - 1] % 2 != sticks[(i + 1) % sticks.Length][sticks[(i + 1) % sticks.Length].Count - 1] % 2 ||
                                 sticks[(i + 2) % sticks.Length].Count > 0 && sticks[i][sticks[i].Count - 1] % 2 == sticks[(i + 2) % sticks.Length][sticks[(i + 2) % sticks.Length].Count - 1] % 2 ||
                                 sticks[(i + 2) % sticks.Length].Count > 0 && sticks[i][sticks[i].Count - 1] > sticks[(i + 2) % sticks.Length][sticks[(i + 2) % sticks.Length].Count - 1])) {
                                lastTargetStick = (i + 1) % sticks.Length;
                            } else {
                                lastTargetStick = (i + 2) % sticks.Length;
                            }
                            Console.WriteLine("Nr. {0} von {1} nach {2}", sticks[i][sticks[i].Count - 1], i + 1, lastTargetStick + 1);
                            sticks[lastTargetStick].Add(sticks[i][sticks[i].Count - 1]);
                            sticks[i].RemoveAt(sticks[i].Count - 1);
                            break;
                        }
                    }
                }
            }
            
        }

Thema: Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
Am im Forum: Smalltalk

Als Fan von Türme von Hanoi musst ich es natürlich gleich probieren.

Hier meine Lösung:

 
        static void Main(string[] args) {
            for (int i = 1; i < 7; i++) {
                Console.WriteLine("== {0} =============================", i);
                Move(i);
            }
        }

        static void Move(int n) {
            Stack<int>[] sticks = new Stack<int>[3];

            for (int i = 0; i < sticks.Length; i++) { 
                sticks[i] = new Stack<int>(); 
            }
            //Fill Stick 1
            for (int i = n; i > 0; i--) {
                sticks[0].Push(i);
            }


            int lastTargetStick = -1;


            while (sticks[0].Count > 0 || sticks[1].Count > 0) {
                for (int i = 0; i < sticks.Length; i++) {
                    if (lastTargetStick != i && sticks[i].Count > 0) {
                        if (sticks[(i + 1) % sticks.Length].Count == 0 && sticks[(i + 2) % sticks.Length].Count == 0) {
                            if (sticks[i].Count % 2 == 0) {
                                lastTargetStick = (i + 1) % sticks.Length;
                            } else {
                                lastTargetStick = (i + 2) % sticks.Length;
                            }
                            Console.WriteLine("Nr. {0} von {1} nach {2}", sticks[i].Peek(), i+1, lastTargetStick+1);
                            sticks[lastTargetStick].Push(sticks[i].Pop());
                            break;
                        } else {
                            if (sticks[(i + 1) % sticks.Length].Count > 0 && sticks[i].Peek() > sticks[(i + 1) % sticks.Length].Peek() &&
                                sticks[(i + 2) % sticks.Length].Count > 0 && sticks[i].Peek() > sticks[(i + 2) % sticks.Length].Peek()) {
                                continue;
                            }
                            if ((sticks[(i + 1) % sticks.Length].Count == 0 || sticks[i].Peek()      < sticks[(i + 1) % sticks.Length].Peek())    && 
                                (sticks[(i + 1) % sticks.Length].Count > 0 && sticks[i].Peek() % 2 != sticks[(i + 1) % sticks.Length].Peek() % 2 ||
                                 sticks[(i + 2) % sticks.Length].Count > 0 && sticks[i].Peek() % 2 == sticks[(i + 2) % sticks.Length].Peek() % 2 ||
                                 sticks[(i + 2) % sticks.Length].Count > 0 && sticks[i].Peek()      > sticks[(i + 2) % sticks.Length].Peek())) {
                                lastTargetStick = (i + 1) % sticks.Length;
                            } else {
                                lastTargetStick = (i + 2) % sticks.Length;
                            }
                            Console.WriteLine("Nr. {0} von {1} nach {2}", sticks[i].Peek(), i+1, lastTargetStick+1);
                            sticks[lastTargetStick].Push(sticks[i].Pop());
                            break;
                        }
                    }
                }
            }
            
        }
    }

Ich hoffe Stacks als Repräsentation der Stäbe sind erlaubt, sonst baue ich es noch um auf Arrays.

Thema: [erledigt] DeadLock, aber warum?
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Mach mal aus den beiden Invokes, jeweils ein BeginInvoke.

Invoke wartet ja bekanntlich darauf, dass der GUI Thread bereit ist eine Aktion auszuführen und führt die die Aktion dann im GUI Thread und warted bis diese fertig ist.
Nun ist aber dein GUI Thread Blockiert und und wartet darauf das die Thread-Methode den Lock aufhebt. Ergo Deadlock.

Irgendwo gabs hier ma

Thema: Beliebte Nicht-Browser-Online-Software
Am im Forum: Smalltalk

Also spontan fallen mir

  • Google Earth
  • iTunes Musikshop
  • Online Poker Clients
  • Diverse Onlinespiele

ein.

Thema: Neue Suchmaschine: Wolfram Alpha
Am im Forum: Smalltalk

Nein, bei denen ist es doch jetzt erst ~7 Uhr morgens

edit: ich meine 6 Uhr,
also bei uns müsste es um 2 Uhr Morgens losgehen

Thema: Neue Suchmaschine: Wolfram Alpha
Am im Forum: Smalltalk

Es ist so weit:

Laut Blog von Wolfram Alpha geht es heute Nacht mit einem Live-Webcast los, an dessen Ende WA Online sein soll:

Zitat
We’ll be making our first attempt to go live with Wolfram|Alpha this Friday evening, May 15. We’ll start webcasting our preparations at 7pm CDT (UTC -5). We’ll work through checklists, do a final test of our infrastructure—and then, if all goes well, within an hour or two we’ll have Wolfram|Alpha live on the public web for the first time. Along the way, we’ll include behind-the-scenes views of what it’s taken to create Wolfram|Alpha.
(Quelle: http://blog.wolframalpha.com/2009/05/12/going-live-and-webcasting-it/)

Der Eintrag ist von Dienstag, und auch im gestrigen wird nochmal bastätigt, das WA heute online gehen soll.

Hier noch der Link zum Webcast: http://www.justin.tv/wolframalpha

greets

Thema: String als Array Index
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hi,

Hier hat Paul Welter in seinem Blog ein XML-Serialisierbares Dictionary veröffentlicht.
Damit müsste es dann auch mit dem XML-Serializer funktionieren.

greets

Thema: Plötzlich werden verschiedene Typen usw. nicht mehr erkannt
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

[offtopic]
Die Logik dahinter ist wahrscheinlich, dass Strg+Shift+U in Uppercase wandelt.
[/offtopic]

Thema: Schach-KI "Battle"
Am im Forum: Projekte

Hier gibts so eine Challenge mit Schiffe-Versenken KIs

Thema: iPod Touch / iPhone als Spielcontroller...
Am im Forum: Smalltalk

Da wäre es vermutlich einfacher / billger eine Wii-Mote(kostet ca. 50€) dafür zu verwenden.
Hier gibt es zudem schon eine Bibliothek um Lagesensoren, IR-Cam, Tasten per .Net auszulesen.

Thema: Suche Programm um den kompletten Verkehr auf einem Port zu überwachen
Am im Forum: Smalltalk

Sorry, es war nicht portmap.port sondern tcp.port == ...

Thema: Suche Programm um den kompletten Verkehr auf einem Port zu überwachen
Am im Forum: Smalltalk

Hi,

Wireshark ist denke ich genau was du suchst.

(Bei Filter noch portmap.port == deinport und fertig)

greets

Thema: C++: Friend-Methoden? Polymorphie nur über Zeiger? Arrays vs. Zeiger auf das erste Element?
Am im Forum: Rund um die Programmierung

1. Da der Operator hier in keiner Klasse ist wird ein Linkes und ein Rechtes Argument benötigt
2/3/4 Der Operator hier ist ausserhalb einer Klasse -> kein this, er ist nicht private, nur die Methode (bzw. der Operator) erhalten zugriff.

5. Man könnte ihn in-Place Implementieren oder einfach auch mit ins Cpp file und halt ohne Classname::

Man könnte es mit einer extention Method von C# vergleichen, wo der std::stream um eine Überladung des << Operaors erweitert wird und der Parameter stream quasi das this bei der extention Method wäre.

std::ostream & operator << (std::ostream & stream, A const & a)


A a1, a2;

  cout  <<   a1 << a2;
//  |         |     |
//stream      a     |
//\___________/     |
//         |        |
//       stream     a

greets

PS:
Zitat

	const int* pInt=0;
	int a=5;
	pInt=&a;
	
	for(int i=0;i<10;i++)
	{
		cout<<pInt[i]<<"\n";
	}
Ich hoffe dir ist klar das du damit schon zwangsläufig eine Zugriffsverletzung hast.

Thema: C++: Friend-Methoden? Polymorphie nur über Zeiger? Arrays vs. Zeiger auf das erste Element?
Am im Forum: Rund um die Programmierung

Hab noch nicht ernstzunehmend mit Managed C++ gearbeitet, was ich aber bisher gesehen habe ist es wirklich eine Perversion.

Wie gesagt musst du die meisten Systemincludes ohne .h angeben
(Unter VisualStudioInsterlationsverzeichniss\VC\include sieht man auch, dass iostream, string, ... kein .h als Endung haben)

Thema: C++: Friend-Methoden? Polymorphie nur über Zeiger? Arrays vs. Zeiger auf das erste Element?
Am im Forum: Rund um die Programmierung

Hi

1) Friends:
Ein Beispiel für friends ist, dass man bei für eine Klasse den Ausgabeoperator überläd. Es kann also durchaus sinnvoll sein, dass bestimmte Klassen/Methoden auf private Member zugreifen können.
(Ein Code sagt mehr als tausend Worte:)


class A {
private: 
   int m_A;

  friend inline std::ostream & operator << 
		(std::ostream & stream, A const & a);
};
...
//.Cpp:
std::ostream & operator << (std::ostream & stream, A const & a){
   stream << "A: " << a.m_A;
   return stream;

//...
A a;
cout << a;
}
Zitat
was mir weiterhin rätselhaft, bzw. nicht sinnvoll vorkommt, ist, dass C++ Polymorphie nur auf Zeigern (und Referenzen?) unterstützt
Das ist doch in C# auch nicht anders, nur dass hier bei Klassen immer gleich automatisch die Referenz gespeichert wird.

Die Anzahl der Elemente in Arrays weis ich auch nicht wo das beim allokieren im hintergrund gespeichert wird, man hat jedenfalls keine Möglichkeit darauf zuzugreifen.

int main()
{
int* Werte=new int[3];
*Werte=2; //erstes Objekt=2
*(Werte+1)=3; //2. Objekt=3//geht das? ... JA (stichwort Pointerarithmetik)

delete [] Werte; //er löscht alle, also muss er wissen, wie viele es sind.
                          //speichert er diese Anzahl irgendwo?

//und wenn ein Array ein Zeiger ist, ist ein Zeiger auch ein Array, oder?
int a=5;
int* pa=&a;
cout<<pa[0]; //geht das?   JA
return 0;
}

cout nimmt er nicht, da du den wahrscheinlich den std nicht eingebunden hast
also:
Zitat
#include <iostream> //hier ohne .h

using namespace std;

int main () {

greets

Thema: C programmieren mit Visual Studio
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

HI,

Einfach die Dateiendung von .cpp auf .c ändern, dann wird meines Wisses der C Compiler verwendet.

greets

Thema: Mit Reflection rausfinden, in welchem Property sich aufgerufene Methode befindet
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hi,

Ich hatte selbst mal versucht, das InotifyPropertyChanged auf basis dieses Threads zu verallgemeinern. Ich habe dabei den Property-Name mittels folgenden Code ermittelt.
Allerdings habe ich diese Methode wieder verworfen, da sie ca. !!500!! mal länger dauert.


    public class Test : INotifyPropertyChanged, INotifyPropertyChanging {
        public event PropertyChangingEventHandler PropertyChanging;
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) {
            if (PropertyChanged != null) PropertyChanged(this, e);
        }
        protected virtual void OnPropertyChanging(PropertyChangingEventArgs e) {
            if (PropertyChanging != null) PropertyChanging(this, e);
        }

        protected bool Notify<T>(ref T oldValue, T newValue) {
            StackTrace trc = new StackTrace();
            MethodBase calling = trc.GetFrame(1).GetMethod();

            if (!calling.IsSpecialName || !calling.Name.StartsWith("set_"))
                throw new Exception("Calling Method is not a setter of a Property");

            PropertyInfo pi = this.GetType().GetProperty(calling.Name.Substring(4));
            return Notify(pi.Name, ref oldValue, newValue);
        }
        protected bool Notify<T>(string propertyName, ref T oldValue, T newValue) {
            if (oldValue == null && newValue == null) {
                return false;
            }
            if ((oldValue == null && newValue != null) || !oldValue.Equals((T)newValue)) {
                OnPropertyChanging(new PropertyChangingEventArgs(propertyName));
                oldValue = newValue;
                OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
                return true;
            }
            return false;
        }

        private int m_A;
        public int A {
            get { return m_A; }
            set { Notify(ref m_A, value); }
        }

        private int m_B;
        public int B {
            get { return m_B; }
            set { Notify("C", ref m_B, value); }
        }

    }