Variable als Verknüpfung als Argument übergeben

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 29 Antworten in diesem Thema. Der letzte Beitrag () ist von siycah.

    Variable als Verknüpfung als Argument übergeben

    Hallo miteinander :)

    Ich hab mal eine recht einfache Frage:

    Ist es irgendwie möglich, einer Sub ein Argument als Verknüpfung mit einer Variable zu übergeben?

    Ich meine jetzt nicht ByRef. Es soll nicht möglich sein, die Variable von der aufgerufenen Sub zu verändern, sondern dass wenn sich die Variable ändert, die Klasse, in der die Sub ist, irgendwie mitbekommt? Ohne zu wissen, wie die Variable heisst, sondern nur anhand der übergebenen Verknüpfung...
    Poste mal bitte nen PseudoWunschCode.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @kafffee So wie ich das verstehe: Raise ein Event.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany

    Wenn ich denke wie du denkst, dann seh ich da keinen Weg. Ich könnte ja dann einfach im Setter von streamfx() (s. unten) den Wert an Klasse2.sourcechannel übergeben. Sorry ich hatte "Variable" statt "Property" geschrieben. Klasse 1 kommt aber an den Namespace von Klasse 2 nicht ran, wohl aber umgekehrt...

    Aber ich bin nicht sicher, ob ich da gleich denke wie du, aber wahrscheinlich meinst du ein Event feuern, wenn sich streamfx() ändert, und dann im Handler Klasse2.sourcechannel zu setzen...

    Aber vielleicht meinst du anders, poste doch mal bitte zwei drei Zeilen Code, wie du das meinst...

    @VaporiZed

    Ich habe das hier in Klasse 1:

    VB.NET-Quellcode

    1. Private _streamfx() As Integer = {0, 0}
    2. Public Property streamfx(index As Integer) As Integer Implements IZentraleKlasse.streamfx
    3. Get
    4. Return _streamfx(index)
    5. End Get
    6. Set(value As Integer)
    7. _streamfx(index) = value
    8. End Set
    9. End Property


    Und das hier in Klasse 2:

    VB.NET-Quellcode

    1. Public Sub New(_sourcechannel As Verknuepfung) 'Statt einen Wert zu übergeben, soll im Idelafall hier eine Verknüpfung übergeben werden
    2. MeineVerknuepfung = _sourcechannel
    3. End Sub
    4. Private MeineVerknuepfung As Verknuepfung
    5. Public ReadOnly Property sourcechannel As Integer
    6. Get
    7. Return MeineVerknuepfung(Wert) 'Hier soll der Wert von Klasse1.streamfx(0) returned werden, Klasse 2 hat aber keine Ahnung, wie streamfx(0) heisst
    8. End Get
    9. End Property


    Klasse 1 weiss aber von Klasse 2 nix, sonst könnte ich ja einfach im Setter von streamfx() den Wert an Klasse2.sourcechannel übergeben. Dahingegen weiss Klasse 2 etwas von Klasse1, aber nicht wie streamfx() heisst.

    Es ist eigentlich ein WPF MVVM typisches Problem, ich dachte trotzdem, dass es besser wäre in diesem Unterforum zu posten, weil ich dachte, es ist eine allgemeine Frage... Ich hoffe das geht klar...
    @kafffee OK. Wie wäre es mit einem Delegate?
    (letzten Endes ist ein Event auch ein Delegate.)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Wenn Klasse1 die Klasse2 nicht kennt, wie soll die Referenz aus Klasse1 dann in Klasse 2 kommen?

    Hab mir die Frage selbst beantwortet
    Edit @kafffee
    Mann kann da was statisches machen, was anderes fällt mir nicht ein. Ich erstelle zwar die "2. Klasse" in der 1. aber nur zur demonstration.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. LetsTryThis.SetI(1000)
    4. Dim f As New Form2
    5. f.Show()
    6. End Sub
    7. End Class
    8. Public Class LetsTryThis
    9. Private Shared I As Integer
    10. Public Shared Sub SetI(value As Integer)
    11. I = value
    12. End Sub
    13. Public Shared Function GetI() As Integer
    14. Return I
    15. End Function
    16. End Class
    17. Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    18. MessageBox.Show(LetsTryThis.GetI().ToString)
    19. End Sub



    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DTF“ ()

    kafffee schrieb:

    Dim MeineInstanz = New Klasse2(VerknuepfungZu_streamfx(0))
    Genau so.
    Die aufrufende Klasse stellt eine Prozedur bereit, deren Adresse Du per elegat an die Klasse2-Instanz übergibst.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany


    Okay weil die Alternative wäre das hier:

    VB.NET-Quellcode

    1. Public Class Klasse2()
    2. Private WelcheInstanzMeinerKlasseBinIch As Integer
    3. Public Sub New(_WelcheInstanzMeinerKlasseBinIch As Integer)
    4. WelcheInstanzMeinerKlasseBinIch = _WelcheInstanzMeinerKlasseBinIch
    5. End Sub
    6. Private Sub Eins()
    7. PlayFile(HoleSourceChannel(WelcheInstanzMeinerKlasseBinIch))
    8. End Sub
    9. Private Sub Zwei()
    10. PauseFile(HoleSourceChannel(WelcheInstanzMeinerKlasseBinIch))
    11. End Sub
    12. Public Function HoleSourceChannel()
    13. Select Case WelcheInstanzMeinerKlasseBinIch
    14. Case 0
    15. sourcechannel = Klasse1.streamfx(0)
    16. Case 1
    17. sourcechannel = Klasse1.EinAndererStream
    18. End Select
    19. End Sub
    20. End Class


    Und das dann jedes Mal wenn ich SourceChannel brauche HoleSourceChannel aufrufen...

    Wäre das mit den Delegaten einfacher oder kommt das im Endeffekt aufs Gleiche raus?

    Ich starr grad schon eine halbe Stunde auf die MS Docs von den Delegaten und werd irgendwie net schlau draus...

    Kannst du mir vieleicht ein Codeschipsel posten oder ein Link zu nem guten Tutorial über Delegates?

    @DTF

    Ja gut wenn ich sie ändern möchte könnte ich ich das hier machen:

    VB.NET-Quellcode

    1. Public Class Klasse2()
    2. Public Sub New (ByRef WelcheVariableBraucjeIch)


    Also vorausgesetzt wenn ich deine Code richtig verstehe...

    Coole Sache das ByRef eigentlich, hilft mir hier aber glaube ich nicht weiter...

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „kafffee“ ()

    Hast du noch nie mit der Bass delegates verwendet? Die hat doch auch so einige wie SYNCPROC z.B.
    Genauso ist das realisiert.

    C#-Quellcode

    1. public partial class Form1 : Form
    2. {
    3. public Form1()
    4. {
    5. InitializeComponent();
    6. }
    7. public delegate string FunctionsDelegate(string name);
    8. private Something theClass;
    9. private void Form1_Load(object sender, EventArgs e)
    10. {
    11. FunctionsDelegate del = new FunctionsDelegate(GetThatString);
    12. theClass = new Something(del);
    13. MessageBox.Show(theClass.GetTheValue("Kafffee"));
    14. }
    15. public string GetThatString(string name)
    16. {
    17. return "Hello " + name;
    18. }
    19. private class Something
    20. {
    21. FunctionsDelegate theFunctionDelegate;
    22. public Something(FunctionsDelegate theFunctionDelegate)
    23. {
    24. this.theFunctionDelegate = theFunctionDelegate;
    25. }
    26. public string GetTheValue(string name)
    27. {
    28. return theFunctionDelegate.Invoke(name);
    29. }
    30. }
    31. }
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    DTF schrieb:

    Hast du noch nie mit der Bass delegates verwendet? Die hat doch auch so einige wie SYNCPROC


    Ja das gute alte SYNCPROC... Verwendet ja, verstanden nein... Damals als ich es implementiert hab hab ich mir das Thema Delegates schon mal angeschaut... und dann irgendwann aufgegeben weil es einfach nicht geschnaggelt hat bei mir...

    Ich hab mir jetzt auch mal ein gefundenes Tutorial reingezogen und deinen Code angeschaut, aber es hat immer noch net Klick gemacht. Ich werd mich jetzt mal auf meine schwarze Wundercouch legen, die bringt immer die besten Ideen wenn ich nicht mehr weiter weiss bzw. vielleicht fällt bei mir über Nacht der Groschen, wär nicht das erste Mal...

    So far, kafffee
    Nimm zur Not einen Konverter wenn du VB besser lesen kannst.
    Ja manchmal ist das so, die besten Ideen hab ich an den unmöglichsten Orten. Vorallem in der Badewanne wo ich nix testen kann oder auf dem Thron(klo).
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Moin Kafffee!

    Das was du hier erreichen möchtest, wäre doch am einfachtsten mit einem Event zu lösen?

    Das, was DTF hier vorgeschlagen hat ist ein Callback, eigentlich genau das gleiche wie ein Event, nur das .Net viele schöne standardisierte Wege hat, Events zu behandeln.

    Anbei noch (natürlich in C#) ein kleines Anschauungsbeispiel, als Komplement zu DTF's Antwort.

    C#-Quellcode

    1. // MyEvent.cs
    2. public delegate void MyEventHandler(object? sender, MyEventArgs e);
    3. public class MyEventArgs: EventArgs {
    4. public MyEventArgs(string propName, object? previous, object? newValue) {
    5. PreviousValue = previous;
    6. NewValue = newValue;
    7. PropertyName = propName;
    8. }
    9. public string PropertyName { get; }
    10. public object? PreviousValue { get; }
    11. public object? NewValue { get; }
    12. }
    13. public interface IMyValueChanged {
    14. public event MyEventHandler? MyEvent;
    15. }


    C#-Quellcode

    1. // Class1.cs
    2. public class Class1: IMyValueChanged {
    3. public event MyEventHandler? MyEvent;
    4. private Class2 m_class2;
    5. public Class1() {
    6. m_class2 = new Class2(this);
    7. }
    8. private int m_myValue = 0;
    9. public int MyValue {
    10. get => m_myValue;
    11. set {
    12. var old = m_myValue;
    13. m_myValue = value;
    14. MyEvent?.Invoke(this, new MyEventArgs(nameof(MyValue), old, value));
    15. }
    16. }
    17. }


    C#-Quellcode

    1. // Class2
    2. public class Class2 {
    3. private IMyValueChanged m_caller;
    4. public Class2(IMyValueChanged caller) {
    5. m_caller = caller;
    6. m_caller.MyEvent += SomeValueChanged;
    7. }
    8. private void SomeValueChanged(object? sender, MyEventArgs e) {
    9. Console.WriteLine($"{ e.PropertyName } hat sich geändert! Alter Wert: { e.PreviousValue }; neuer Wert: { e.NewValue }");
    10. }
    11. }


    Das Ganze habe ich ein bisschen an INotifyPropertyChanged angelehnt, was aber einen direkten Verweis auf das Objekt braucht, was du ja (scheinbar? vielleicht verlese ich mich ja) nicht möchtest.

    Vielleicht bringt dich das ja auf eine zündende Idee!
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems
    Meine Privatwebseite: SimonC.eu

    Bitte nicht wundern, wenn meine Aktivitäten im Forum etwas langsamer sind, ich baue gerade mein Nebengewerbe zum Vollgewerbe aus.
    Ich versuche auf euch zurückzukommen :)
    Okay aber einfacher wird mein Code wahrscheinlich nicht damit, oder?

    Stellt euch Folgendes vor:

    Ich habe fünf Instanzen eines ViewModels SingleEffectRack (für die WinFormsler unter den Lesern sei das jetzt mal eine Klasse).
    Diesen möchte ich ich im Konstruktor einen streamHandle As Integer übergeben, der als Property in einem Service MeinService sitzt (für die WinFormsler: das ist auch eine Klasse, und zwar eine, auf die man von SingleEffectRack zugreifen kann, dies aber nicht andersrum geht)
    für jede Instanz einen anderen streamHandle

    So in ungefähr.

    Nun kann sich aber während der Laufzeit eben dieser streamHandle ändern, und meine SingleEffectRacks sollen das mitbekommen.

    Das hätte ich jetzt bisher so gemacht:

    In den Konstruktoren einfach ein Integer mitgeben, für die erste Instanz eine 0, für die zweite Instanz eine 1 usw... und in meinem SingleEffectRack eine Funktion haben:

    VB.NET-Quellcode

    1. Private Function GetStreamValue(WelcheInstanz As Integer)
    2. Select Case 0
    3. Return MeinService.stream1
    4. Select Case 1
    5. Return MeinService.stream2
    6. Select Case 2
    7. Return MeinService.Master
    8. usw...
    9. End Function


    Jetzt war meine Frage, obs da sowas ähnliches wie ein ByRef gibt, wo ich in den Konstruktoren direkt Verweise auf die Properties in MeinService mitgeben kann, sodass meine ViewModel-Klassen das mitbekommen.

    Das wär natürlich ideal.

    Wenn ich das richtig verstehe, müsste ich dann aber, wenn ich diese Delegates benutze, trotzdem irgendwo dann so eine Select...End Select-Sache einbauen oder?

    Ich habs mir jetzt ewig lang angeschaut, aber vielleicht kommt dann morgen irgendwann der Geistesblitz.
    Bleibt dran mit den Delegates, als RodFromGermany das erwähnte dachte ich mir auch, ja daran hättest du auch denken können. Mir fiel aber nur der statische Mist ein.

    Das delegate zeigt auf die Sub/Funktion, mit delegate.Invoke(BgineInvoke) wird die zugewiesen Sub/Funktion aufgerufen. Das ist keine Hexerei und genau das was du brauchst.

    Jede Sub/Funktion in deinem Programm ist zur Laufzeit an irgendeiner Adresse im Speicher zu finden, diese Adresse ist halt in der Instanz die du anlegst, dann wird die Sub/Funktion an dieser Adresse aufgerufen. Wichtig ist dabei das die Rückgabetyp und Parameter anzahl wie auch dessen Typen identisch sind. Sieh mal genau hin, dann solltest du sehen was gemeint ist.

    C#-Quellcode

    1. public delegate string FunctionsDelegate(string name);
    2. public string GetThatString(string name){return ....}

    FunctionsDelegate del = new FunctionsDelegate(GetThatString); => zeigt auf die Funtion GetThatString in der Form1-Instanz.

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „DTF“ ()

    Das bedeutet es kann null/nothing sein. Das ist ein Feature von .NET, man bekommt Hinweise im Studio was wann wo null sein darf oder auch sein könnte, für Anfänger möglicherweise gut, auch wenn jemand anderes deinen Code wartet. Aber ich schalte das bei mir aus, ich weiß in meinem Code was wo null sein darf oder sein könnte, mich nervt dieses Feature.
    In einem Net-Projekt mach mal einen Doppelklick im Solution-Explorer auf ein Projekt, da findest du dann neben anderen diese Zeile:

    XML-Quellcode

    1. <Nullable>disable</Nullable>

    Default ist das enabled.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Tut mir leid, ich steig da beim besten Willen nicht durch. Hab mal versucht einen eigenen Rewrite von euren Codes zu machen und das quasi für mich "umzushreiben"... aber ist gescheitert... Kann mir jemand konkret zeigen wie er das an meiner Stelle machen würde, vielleicht versteh ichs dann. Am besten mit den Namen die ich oben verwendet habe.

    Ich glaub es ist weniger der Code als die Idee die dahinter steckt. Es kommt mir nicht in den Sinn wir mir das die Arbeit erleichtern soll... vielleicht erwarte ich was völlig anderes...

    Ich hab ja in Post 16 denke ich ausführlich genug gezeigt, was meine Intention ist... Aber irgendwie habt ihr eine andere Sichtweise auf das Problem wie ich...