Click here to Skip to main content
16,022,069 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I found the following example in order to pass C# Properties by ‘ref’ to a method but I don't understand it very well and I have some questions please.

C#
<pre>
class Class1
{
    public int PropertyValue1 { get; set; }
}

class Class2
{
    public void UpdateProperty(Action<int> setValue)
    {
        setValue(100);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Class1 class1 = new Class1();
        Class2 class2 = new Class2();

        Action<int> setPropertyValue1 = (value) => 
        { class1.PropertyValue1 = value; };
        class2.UpdateProperty(setPropertyValue1);

        Console.WriteLine(class1.PropertyValue1); // Output: 100
    }
}



In Class2 I don't understand very well UpdateProperty, especially the Action<int> what does an action of a data type do?
setValue(100);
how should setValue be called for any value I would like to pass? I don't understand it.

I also don't understand these two lines
Action<int> setPropertyValue1 = (value) => 
        { class1.PropertyValue1 = value; };
     class2.UpdateProperty(setPropertyValue1);


Any explanation would be much appreciated. Thank you so much in advanced.

What I have tried:

C#
delegate void PropertySetterDelegate(int value);

class Example
{
    public int PropertyValue1 { get; set; }
    public int newValue { get; set; }

    public void UpdateProperty(PropertySetterDelegate setter)
    {
        setter(newValue);
    }
}
class Program
{
   static void Main(string[] args)
   {
      Example ex = new Example();
      ex.newValue = 435;
      PropertySetterDelegate setter = delegate (int value)
      { ex.PropertyValue1 = value; };

      ex.UpdateProperty(setter);

      Console.WriteLine("PropertyValue1: " + ex.PropertyValue1);
   }
}


According the first way it could be like the following but I still haven't understood it very well.

C#
class Class1
{
   public int PropertyValue1 { get; set; }
   public static int newValue { get; set; }
}

class Class2
{
   public void UpdateProperty(Action<int> setValue)
   {
      setValue(Class1.newValue);
   }
}
static void Main(string[] args)
{
    //b tropos
    Class1 class1 = new Class1();
    Class2 class2 = new Class2();

    //class1.PropertyValue1 = 50;
    Class1.newValue = 50;
    Action<int> setPropertyValue1 = (value) =>
    { class1.PropertyValue1 = value; };
    class2.UpdateProperty(setPropertyValue1);

    Console.WriteLine(class1.PropertyValue1); // Output: 50

    Console.ReadLine();
}
Posted
Updated 14-Sep-24 5:50am
v2

System.Action<T> is a delegate, basically meaning that using it you can define any method to be called as long as the signature is the same. In your example the Action<int> parameter defines the types to be used so you need a method that has the signature as
C#
void SomeMethod(int parameterValue)


Now in the calling code you have an anonymous method stored in a variable setPropertyValue1
C#
Action<int> setPropertyValue1 = (value) => 
        { class1.PropertyValue1 = value; };

The method above gets one integer value (named value) as a parameter and whenever called the code assigns the value from the parameter to class1.PropertyValue1 in other words when called, the code below is executed
C#
{ class1.PropertyValue1 = value; }


Now since a 'pointer' to this method is stored in the setPropertyValue1 it can be used as a parameter to the next call. The main method calls
C#
class2.UpdateProperty(setPropertyValue1);

That means that the method in Class2 actually calls the anonymous method described earlier. The call from Class2 is
C#
setValue(100);

so that means that the anonymous method is called using 100 as the parameter value.

From what I gather from the things you have tried, it looks like you want to set the value from outside Class2. If that is the case, then modifying the code slightly, would probable be what you're looking for

C#
static void Main(string[] args) {
   Class1 class1 = new Class1();
   Class2 class2 = new Class2();

   // Define the anonymous method to be used for setting the property
   Action<int> setPropertyValue1 = (value) =>
   { class1.PropertyValue1 = value; };
   // Call the anonymous method and pass 50 as the value to be set
   class2.UpdateProperty(setPropertyValue1, 50);

   Console.WriteLine(class1.PropertyValue1); // Output: 50
}

class Class1 {
   public int PropertyValue1 { get; set; }
}

class Class2 {
   // Define the method to have two parameters, 
   // one for the method to be called and second one for the value to be used
   public void UpdateProperty(Action<int> setValue, int valueToSet) {
      setValue(valueToSet);
   }
}
 
Share this answer
 
Comments
Aggeliki Asimakopoulou 15-Sep-24 4:23am    
Thank you so much. I have a question please. All this functionallity with delegates and Actions is it possible to be used for a buttons Enable property that belong to a running form FormOne, in order to change the value from another opened form FormTwo while is being closed FormTwo? Thank you so much in advanced.
Wendelius 15-Sep-24 6:21am    
Well, technically you could do that but it does not make sense. Functionality between the two forms should not be tied together like that. Instead you should separate the logic for the forms so that either one is not tightly coupled to the other.

There are several examples available how to exchange information between forms. The three part series mentioned by OriginalGriff in solution 1 is definitely worth while reading
Aggeliki Asimakopoulou 15-Sep-24 7:17am    
The problem here is that I have a form named OrdersForm in which I am able to load an order by searching criteria. This form includes two buttons, CreditInvoiceIssuanceBtn and ViewCreditInvoiceBtn. So, when somebody returns an order product, I am able from OrdersForm to press CreditInvoiceIssuanceBtn if a CreditInvoiceIssuance doesn't exist for that order and CreditsOrderDocumentForm opens I save the Invoice for the returning product, I close CreditsOrderDocumentForm and CreditInvoiceIssuanceBtn of OrdersForm should be disabled and ViewCreditInvoiceBtn enabled. That's the reason both forms should coperate.
Passing by ref isn't like that - it's a specific way to pass a variable to a method so that the original variable is changed.
Under normal circumstances when you call a method and pass a parameter to it, it is passed by value - a copy of the variable is passed over, and any changes to that do not alter the value in the calling method:

C#
static void foo(int x)
   {
   Console.WriteLine(x);
   x += 111;
   Console.WriteLine(x);
   }
static void Main(string[] args)
   {
   int y = 666;
   Console.WriteLine(y);
   foo(y);
   Console.WriteLine(y);
   }
Will print this:
Results
666
666
777
666
Passing by ref is different: a reference to the original variable is passed instead of a copy:
C#
static void foo(ref int x)
   {
   Console.WriteLine(x);
   x += 111;
   Console.WriteLine(x);
   }
static void Main(string[] args)
   {
   int y = 666;
   Console.WriteLine(y);
   foo(ref y);
   Console.WriteLine(y);
   }
Will print this:
Results
666
666
777
777
Because the original variable in the calling code is passed to the method instead of a new variable being created.

Your code doesn't do that: it does not involve pass by reference at all!
Instead, the code you found creates an anonymous delegate , which is entirely different - it creates a unnamed method, and then executes that.

Action is a delegate type that doesn't return a value: Action<T> Delegate (System) | Microsoft Learn[^]

I would strongly suggest that you read your assignment again carefully, and stop grabbing code from the internet in the hope that it'll do exactly what you need to hand in - I have no idea what your tutor assigned you, but there is a good chance that you need to study the course material pretty carefully as you don;t seem to understand stuff that is pretty fundamental going forward!
 
Share this answer
 
Comments
Aggeliki Asimakopoulou 15-Sep-24 4:31am    
Thank you so much but I refered to properties of a class, not simple variables that are being passed by reference. So the purpose for me, that I didn't mentioned above, is not to change property values through some methods, but dynamically change some buttons Enabled Values from another form while is being closed to the remained opened previous form. So that when is being closed the second form the Enable values properties of the previous to be changed. That's why the article I found on the web serves me for that purpose. But I hadn't understood it very well. However thank you so much for your reply.
OriginalGriff 15-Sep-24 5:38am    
Don't do it like that - a form shouldn't know about how another form works, unless it opens the other form. If it does, then that breaks OOPs design as you can no longer alter either form without taking account of change that might break other code, and it also restrict the reusability of either form

Exactly how you should do it depends on the "relationship" between the two forms.
Have a look at these, one of them will fit your circumstances.
The form that creates an instance of another:
MyForm mf = new MyForm();
mf.Show();
Is the "parent", the other form is the "child".
(This doesn't imply any formal MDI relationship)

Transferring information between two forms, Part 1: Parent to Child[^]
Transferring information between two forms, Part 2: Child to Parent[^]
Transferring information between two forms, Part 3: Child to Child[^]
Aggeliki Asimakopoulou 15-Sep-24 6:32am    
Sure, I tried that and my problem is when form2 is closed, the form1 buttons enabled values changes to the instance, not to the actual form form1 that is running, that is why I face that problem!
OriginalGriff 15-Sep-24 7:19am    
no, you ar egoign to have to explain that in better detail - remember that we can't see your screen, access your HDD, or read your mind - we only get exactly what you type to work with - we get no other context for your project.
Aggeliki Asimakopoulou 15-Sep-24 7:38am    
You are right, that's why I searched on the web, I found this article, but it was something new to me and was trying to undertand it and because I didn't I asked for explanation about this. You are very welcome. I made it work and I will post the solution above. C# is very powerful programming language and I have so many to learn and knowledge is unlimited.
I would like to share the solution in my problem, I mentioned after the fact.
public static class OrdersFormUtilityClass 
{
   public delegate void PropertySetterDelegate(bool value);

   public static bool CreditInvoiceBtnEnabled { get; set; }
   public static bool ViewCreditInvoiceBtnEnabled { get; set; }

   public static bool CreditInvNewValue { get; set; }
   public static bool ViewCreditInvNewValue { get; set; }

   public static void UpdateCreditInvoiceIssuanceBtnState(PropertySetterDelegate setter)
   {
       setter(CreditInvNewValue);
   }

   public static void UpdateViewCreditInvoiceBtnState(PropertySetterDelegate setter)
   {
       setter(ViewCreditInvNewValue);
   }

   public static void DynamicChangeBtnsState(ref Button btn)
   {
       if (btn.Name.Equals("CreditInvoiceIssuanceBtn"))
       {
           btn.Enabled = CreditInvNewValue;
       }
       else if (btn.Name.Equals("ViewCreditInvoiceBtn"))
       {
           btn.Enabled = ViewCreditInvNewValue;
       }
   }    
}


private void OrdersCreditDocumentForm_FormClosing(object sender, FormClosingEventArgs e)
{
    SaveSQLquery.FromCreditOrder = false;
    OrdersCreditDocumentForm CreditDocumentForm = this;
            
    if (CreditDocumentForm.SavedInvoice)
    {
        OrdersFormUtilityClass.CreditInvNewValue = false;
        OrdersFormUtilityClass.ViewCreditInvNewValue = true;
    }
    else
    {
        OrdersFormUtilityClass.CreditInvNewValue = true;
        OrdersFormUtilityClass.ViewCreditInvNewValue = false;
    }
                       
            
    OrdersFormUtilityClass.PropertySetterDelegate NewCreditInvBtnSetter = delegate (bool value) 
    { OrdersFormUtilityClass.CreditInvoiceBtnEnabled = value; };

    OrdersFormUtilityClass.PropertySetterDelegate ViewCreditInvBtnSetter = delegate (bool value)
    { OrdersFormUtilityClass.ViewCreditInvoiceBtnEnabled = value; };
            

    OrdersFormUtilityClass.UpdateCreditInvoiceIssuanceBtnState(NewCreditInvBtnSetter);
    OrdersFormUtilityClass.UpdateViewCreditInvoiceBtnState(ViewCreditInvBtnSetter);

    (this.Owner as OrdersForm).CreditInvoiceIssuanceBtn.Enabled = 
    OrdersFormUtilityClass.CreditInvNewValue;
    (this.Owner as OrdersForm).ViewCreditInvoiceBtn.Enabled = 
    OrdersFormUtilityClass.ViewCreditInvNewValue;
           
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900