Laden...

Klasse bekommt eine Referenz via ref von einem primitiven Typ, wie speichern?

Erstellt von Seikilos vor 13 Jahren Letzter Beitrag vor 13 Jahren 1.866 Views
S
Seikilos Themenstarter:in
753 Beiträge seit 2006
vor 13 Jahren
Klasse bekommt eine Referenz via ref von einem primitiven Typ, wie speichern?

Direkt das Beispiel:


public class Foo
{ 
   protected ref bool f_;
   public Foo(ref bool f)
   {
      // wie speicher ich die referenz?
   }
   public ~Foo()
   {
      // benötige hier die referenz auf das Objekt
   }
}

Ich habe eine Klasse die eine Referenz auf einen Bool bekommt, nun muss ich aber diese Referenz aktiv über die Lebenszeit der Klasse irgendwie transportieren.
Gibt es einen Weg einen derartigen Typen abzulegen?

Ich will quasi eine externe Variable im Ctor bekommen und ändern und dies im Dtor ebenfalls tun.

Danke

Life is a short

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo Seikilos,

Gibt es einen Weg einen derartigen Typen abzulegen?

nein, Referenzen auf elementare Datentypen sind nur bei der Parameterübergabe (oder - bäh - über Boxing, was aber hier auch nichts bringt) möglich. Wenn du eine Referenz speichern willst, muss der Parametertyp schon ein Referenztyp sein.

herbivore

T
210 Beiträge seit 2006
vor 13 Jahren

Du könntest statt der Referenz auf die bool Variable zwei Lambda Expressions übergeben, eine die die Variable setzt, eine zweite, die den Wert liefert, sofern Du beides brauchst...

Gruß
T-Man

1.378 Beiträge seit 2006
vor 13 Jahren

Oder du kapselst das Feld in einer eigenen Klasse die du übergibst.

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo T-Man,

kann man natürlich machen. Aber das ist doch ein eher unüblicher und nicht besonders offensichtlicher Weg. Wenn man in die Richtung "Übergabe einer Aktion" gehen will, dann wäre es wohl sinnvoller, einen eigenen Event zu definieren und zu feuern. In den EventArgs kann dann der zu setzende Wert übergeben werden.

Hallo xxxprod,

Oder du kapselst das Feld in einer eigenen Klasse die du übergibst.

wie ich schon schrieb:

Wenn du eine Referenz speichern willst, muss der Parametertyp schon ein Referenztyp sein.

herbivore

T
210 Beiträge seit 2006
vor 13 Jahren

Das mit dem event klappt aber nicht, wenn er im destruktor den aktuellen Wert lesen möchte.

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo T-Man,

tja, kann sein, aber das bekommst du ja auch nur hin, wenn du zwei Lambdas übergibst. Mindestens genauso gut kann man dann auch zwei Events verwenden. Wenn es aber nur ums Lesen geht, ist ein Event besser als ein Lambda.

herbivore

5.742 Beiträge seit 2007
vor 13 Jahren

Ich will quasi eine externe Variable im Ctor bekommen und ändern und dies im Dtor ebenfalls tun.

Ganz schlechte Idee: Die Instanz, der das Feld eigentlich "gehört" könnte im Finalizer (das ist kein Destruktor - evtl. wird der nie aufgerufen bzw. erst sehr spät) bereits collected worden sein (auch wenn du sie noch referenzierst).
Aus einem Finalizer heraus sollte man niemals auf andere Objekte zugreifen - egal wie.

Evtl. suchst du eher IDisposable.

S
Seikilos Themenstarter:in
753 Beiträge seit 2006
vor 13 Jahren

Was für den Background: Die Foo Klasse erbt von IDisposable und soll so etwas wie ein Event freien Scope bereitstellen.

In einem anderen Thread hab ich gefragt wie man verhindert, das Events gefeuert werden, wenn man bereits in dem Event ist und es nochmal auslöst.
Die Quintessenz war ein bool eventEnabled, den man beim Ausführen des Event-Codes auf false und nach dem Ausführen wieder auf true setzt.

Da ich aber keine Lust habe jedes mal die Flags zu setzen (und es mal vergessen werde 😃 ) und da man den Scope des Eventfreien raums nicht gut erkennt, habe ich den bool tatsächlich in einer Klasse Bool gekapselt.

Diese Klasse wird nun an die Foo Klasse gegeben, welche über using prima einen Scope aufmacht, im Ctor den Bool deaktiviert und im Dispose wieder aktiviert.


using (new EventGate(myBool))
{
  // hier kein Event feuer
}

Zu blöd das ich den Operator = nicht überladen kann, dann könnte der Bool wie ein bool benutzt werden. Aber man kann nicht alles haben.

(Wahrscheinlich gibt es eine bessere Methode und ich erzähl euch eh nichts neues, aber so werden wenigstens ein paar Bytes auf irgend einer Platte mal genutzt bevor sie vergammeln 😄 )

Life is a short

1.378 Beiträge seit 2006
vor 13 Jahren

Den Operator = kannst du nicht überladen aber einen impliziten Cast und damit funktioniert es dann wieder.
Implicit

Lg XXX

//EDIT: Kannst du ein kleines Beispiel posten wie deine Klasse das Ausführen eines Events verhindert? Würd mich auch interessieren. 😃

S
Seikilos Themenstarter:in
753 Beiträge seit 2006
vor 13 Jahren

implicit könnte helfen! Danke 😃

Verhindern tut die Klasse die Ausführung des Events nicht wirklich, aber wenn ich so etwas habe:



protected void einEventHandler()
{
  // Code der wieder diesen Handler aufrufen würde
}


so ist ja eine Möglichkeit die Rekursion zu verhindern in dem man nen bool nimmt



protected void einEventHandler()
{
  if(eventEnabled)
  {
     eventEnabled = false;
     // Code der wieder diesen Handler aufrufen würde, was er aber nicht tut
     eventEnabled = true;
  }
}


Und weil man nun hier öfter immer irgendwo eventEnabled = false; Code; eventEnabled = true; schreiben müsste und man das eine oder andere vergessen könnte, habe ich Foo gebaut, um das eleganter zu Verpacken:


protected void einEventHandler()
{
  if(eventEnabled)
  {
     using(new Foo(eventEnabled))
     {
        // Code der wieder diesen Handler aufrufen würde, was er aber nicht tut
     }
  }
}

Da darf der bool nur kein bool, sondern ein Referenztyp sein

Life is a short

1.378 Beiträge seit 2006
vor 13 Jahren

Cool wärs, wenn man die eventenabled variable und die if abfrage auch nicht brauchen würde. 😃

S
Seikilos Themenstarter:in
753 Beiträge seit 2006
vor 13 Jahren

Wenn das Event im Handler selbst nicht ausgelöst werden kann, kann man das sicher so auch irgendwie lösen. Ich habe aber eine Situation wo eine Methode, die nichts mit dem Handling zu tun hat, Sachen macht, die auch nicht zum Aufruf des Handlings führen dürfen.
Wenn man das dann noch für verschiedene Handler hat, wirds kompliziert.

Ist aber eine interessante Idee und ich werde mal ein wenig drüber nachdenken, ob man das generischer lösen kann.

Edit: Das Problem bei mir ist, dass ein Handler für 40 Controls gleich ist. Sprich ich kann nicht ein Control übergeben (also kann ich schon, aber nützt mir nichts)

Ich müsste irgendwie die Handling Methode an Foo übergeben und es müsste so eine art on the fly Uberschreibung machen, so dass in dem Scope von Foo die Methode nichts macht.

Btw: Implicit hat es wirklich gebracht 😃

Life is a short

1.378 Beiträge seit 2006
vor 13 Jahren

Hab ein kleines Beispiel gebastelt:


    class Program
    {
        static void Main()
        {
            new Action(Bar).BeginInvoke(null, null);
            new Action(Bar).BeginInvoke(null, null);

            Console.Read();
        }

        private static void Bar()
        {
            Console.WriteLine("Entering Eventsafe method.");
            using (new Foo(() =>
            {
                Console.WriteLine("Executing event");
                Thread.Sleep(2000);
            })) ;
        }
    }

    public class Foo : IDisposable
    {
        private readonly Action _action;
        private static readonly List<Action> Actions = new List<Action>();

        public Foo(Action action)
        {
            lock (Actions)
            {
                _action = action;

                if (Actions.Contains(action))
                    return;

                Actions.Add(action);
            }

            action();
        }

        public void Dispose()
        {
            lock (Actions)
            {
                Actions.Remove(_action);
            }
        }
    }

Schöner wärs, wenn man den Code direkt in die Usingklammern schreiben könnte aber das wirds wohl nicht spielen.

😃

1.378 Beiträge seit 2006
vor 13 Jahren

Für was usings. Eine einfach statisch Methode tuts auch:


    class Program
    {
        static void Main()
        {
            new Action(Bar).BeginInvoke(null, null);
            new Action(Bar).BeginInvoke(null, null);

            Console.Read();
        }

        private static void Bar()
        {
            Console.WriteLine("Entering method1.");
            Foo.Bar(() =>
            {
                Console.WriteLine("Executing event1");
                Thread.Sleep(5000);
                Console.WriteLine("Event1 executed");
            });
        }
    }

    public class Foo
    {
        public static void Bar(Action action)
        {
            if (!Monitor.TryEnter(action))
                return;

            action();

            Monitor.Exit(action);
        }
    }