Passing line of code as argument into function - c#

I am looking to pass a line of code into a function I am calling in c# with the intention to optimise my code and attempt to learn something new. I am familiar with using strings, ints, floats, booleans as I have shown in my code.
The idea is to call a function on a button click that stops a script and begins a script again. Without the function this code is working:
public void PlayOnClick()
{
if(count != 1)
{
m_animator.GetComponent<Animator>().Play("Scale");
d_animator.GetComponent<Animator>().Play("CloseUp");
((MovieTexture)MovieOne.GetComponent<Renderer>().material.mainTexture).Play();
Dialyser.GetComponent<RotationByMouseDrag>().enabled = false;
count = 1;
}
else
{
m_animator.GetComponent<Animator>().Play("Scale");
d_animator.GetComponent<Animator>().Play("ScaleDown");
((MovieTexture)MovieOne.GetComponent<Renderer>().material.mainTexture).Stop();
Dialyser.GetComponent<RotationByMouseDrag>().enabled = true;
count = 0;
}
}
However I believe this can be shortened. I have got this so far:
void Lock(string A, string B, ? C, bool D, int E)
{
m_animator.GetComponent<Animator>().Play(A);
d_animator.GetComponent<Animator>().Play(B);
C;
Dialyser.GetComponent<RotationByMouseDrag>().enabled = D;
count = E;
}
In function C I would want to pass the following line when pressed once:
((MovieTexture)MovieOne.GetComponent<Renderer>().material.mainTexture).Stop();
And have it change to this when pressed again:
((MovieTexture)MovieOne.GetComponent<Renderer>().material.mainTexture).Play();
I have come across eval - but I believe that is just for javascript and could be quite processor intensive. I have looked into parsing the line as a string.
I am currently coming up trumps on searches and on attempts. Could anyone shed some light on this for me?

What you are looking for is called delegates, or function pointers in c++ terms.
You can find more on delegates here.
Actions might feel more quicker to code with.
Basically, you can pass a reference to a method you want to execute. The signature of the method should be exactly the same as parameter type declared in the method. So if you expect to pass and run a piece of code that does not return any value, you could use Action type, without any type parameters. For example
class A {
void printAndExecute(String textToPrint, Action voidMethodToExecute) {
Debug.Log(textToPrint);
voidMethodToExecute();
}
}
class B : MonoBehaviour {
void Start() {
new A().printAndExecute("SAY", sayHello);
}
void sayHello() {
Debug.Log("Hello!");
}
}
Hope it helps

You have to pass an Action type or a custom delegate :
void Lock(string A, string B, System.Action C, bool D, int E)
{
m_animator.GetComponent<Animator>().Play(A);
d_animator.GetComponent<Animator>().Play(B);
C();
Dialyser.GetComponent<RotationByMouseDrag>().enabled = D;
count = E;
}
// ...
Lock("Scale", "CloseUp", ((MovieTexture)MovieOne.GetComponent<Renderer>().material.mainTexture).Play, false, 1 ) ;

Related

C# loop over bool values

Is there a concise way to loop over true/false in C#?
I have ~20 lines of code in a unit test I'd rather not duplicate to toggle one boolean true/false.
I could break it off into a function and call it twice, but meh. This code feels more like I'm iterating over possible values than performing a distinct action with different parameters. Even if I had a function, I'd prefer the syntax of looping over the possible values rather than just calling it twice.
I could write a for loop like so...
bool toggle;
for (int i = 0; i < 2; i++)
{
toggle = i == 1;
}
But that doesn't seem very clean.
I like this syntax:
for (bool b : { false, true }) { /* ... */ }
But it doesn't look like that will compile in C#.
Edit:
Following Jeroen's suggestion about local functions and Dmitry's answer, this is the route I went:
[TestMethod]
public void GetAndSetValue()
{
foreach (bool toggle in new [] { false, true })
{
GetAndSetValue(toggle);
}
void GetAndSetValue(bool toggle)
{
// details not important
}
}
Reasonable coders can debate whether the loop reads more easily than two function calls:
GetAndSetValue(false);
GetAndSetValue(true);
I like the loop better, so I'll roll with it until someone complains. Cheers!
Correct syntax will be foreach, not for:
foreach (bool b in new [] { false, true }) {
/* ... */
}
While I think simply writing a parametrized function is definitely the correct approach, the closest to that C++11 syntax that you can get in C# would be:
foreach (bool value in new [] { false, true })
{
// ...
}
I would probably just do it this way, either with a local function:
[TestMethod]
public void GetAndSetValue()
{
GetAndSetValue(false);
void GetAndSetValue(bool toggle)
{
// details not important
if (!toggle)
GetAndSetValue(true);
}
}
Or "old" school with a private method.
[TestMethod]
public void GetAndSetValue()
{
GetAndSetValue(false);
}
private void GetAndSetValue(bool toggle)
{
// details not important
if (!toggle)
GetAndSetValue(true);
}

Showing MessageBox in long running process

In an MVVM application I have a long running calculation that runs
in legacy code.
That legacy code shows a MessageBox to ask the user if it shall continue.
Now I want this code to stick to MVVM as easy as possible and thought
about handing in a callback to show the MessageBox and evaluating the
result inside.
How can this be done the easiest?
Have often seen Action for callbacks, but I have no idea how
to work with the bool inside the legacy code.
I want to pass the string to show in the MessageBox from the legacy code
and return the decision (a bool) to the legacy code.
Please note: I do not have to do a bigger refactoring right now, but want
to get rid of the MessageBox inside the legacy code right now.
Perhaps I can use a function like
private bool ShowMessageBox(string text)
{
var result = MessageBox.Show(text, "", MessageBoxButton.YesNo);
if (result.Equals(MessageBoxResult.Yes))
{
return true;
}
return false;
}
-edit-
Should I use some
Action<string, Action<bool>>
for the method signature?
How can I access the bool in the legacy code?
Maybe you can use a delegate?
For the method you showed, you can create a delegate like this:
public delegate bool ShowMessageBoxDelegate(string text);
Then let's say you have a property using the delegate as the type:
public ShowMessageBoxDelegate ShowMessageBoxDelegateProperty { get; set; }
Now if your ShowMessageBox method matches the signature of this delegate...
public bool ShowMessageBox(string text)
{
var result = MessageBox.Show(text, "", MessageBoxButton.YesNo);
if (result.Equals(MessageBoxResult.Yes))
{
return true;
}
return false;
}
... then you could set it as the value of the ShowMessageBoxDelegateProperty property:
ShowMessageBoxDelegateProperty = ShowMessageBox;
Note the missing parenthesis. A delegate can also be multicast, which simply means that they can have more than one method attached to them:
ShowMessageBoxDelegateProperty += ShowMessageBox;
You can also use them as parameters in methods:
public void ProxyShowMessageBox(ShowMessageBoxDelegate showMessageBoxDelegate)
{
if (showMessageBoxDelegate != null)
{
bool result = showMessageBoxDelegate("MessageBox message");
}
}
You would then call it like this:
ProxyShowMessageBox(ShowMessageBox);
You can find out more from the Delegates Tutorial page at MSDN.

Is it possible to invoke functions used to create parameters for a method from inside that method? (C#)

This is a bit hard to explain, but I'm hoping this example will clear it up.
Say I have some function call Visible:
public bool Visible(/* Some page element */)
{
// Checks if something on a webpage is visible. Returns a "true" is yes, and "false" if not
}
Is it possible to some how wait for this function to return true? What I've written out so far looks like this:
public void WaitUntil(/*function returning bool*/ isTrue)
{
for (int second = 0; ; second++)
{
if (second >= 12)
{
/* Thow exception */
}
else
{
if (isTrue /*calls the isTrue function with given parameters*/)
{
return;
}
}
}
}
Such that these two method could be used together like:
WaitUntil(Visible(/* Some page element */));
to wait until a page element is visible... Is this possible?
Here is how to do it (although you should consider using events as this kind of "waiting" is strongly discouraged)
/*Important Note: This is ugly, error prone
and causes eye itchiness to veteran programmers*/
public void WaitUntil(Func<bool> func)
{
DateTime start = DateTime.Now;
while(DateTime.Now - start < TimeSpan.FromSeconds(12))
{
if (func())
{
return;
}
Thread.Sleep(100);
}
/* Thow exception */
}
//Call
WaitUntil(() => Visible(/* Some page element*/));

Removing Text with an Invoke?

So, the documentation that I've found online so far regarding the Invoke property doesn't seem to be particularly good, which is actually kind of annoying, believe it or not. I understand what Invoke does - you can't safely access the GUI directly, so an invoke does it in a safe way. That's fine, but I don't understand the variables that go into the method. If I wanted to, for instance, remove text from a listbox, how would I do that? I get about this far before I get a bit lost.
private void DoStuff(string TextIWouldBeRemoving)
{
if (listboxname.InvokeRequired)
{
listboxname.Invoke(SomeMysteriousParamaters, new object[] { TextIWouldBeRemoving )};
}
}
The first parameter is the method you want to safely invoke, the second parameter is an object array of the arguments to that method
So you would write:
private void DoStuff(string TextIWouldBeRemoving)
{
if (listboxname.InvokeRequired)
{
listboxname.Invoke(DoStuff, new object[] { TextIWouldBeRemoving )};
}
else
{
// Actually remove the text here!
}
}
Invoke is all about threading.
You need to do an invoke whenever you have created a separate thread in your code, and you need to update the User Interface elements from withing the code, that is executing in that newly create thread.
You can use a BeginInvoke, instead of a synchronous Invoke method. This article has a good example:
http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx
private void button1_Click(object sender, EventArgs e)
{
if (listBox1.InvokeRequired)
{
Action<string> d = DoAnything;
listBox1.Invoke(d, new object[] { "Item 1" });
}
else
DoAnything("Item 1");
}
void DoAnything(string itemText)
{
listBox1.Items.Remove(itemText);
}

Detailed Explanation of Variable Capture in Closures

I've seen countless posts on how variable capture pulls in variables for the creation of the closure, however they all seem to stop short of specific details and call the whole thing "compiler magic".
I'm looking for a clear-cut explanation of:
How local variables are actually captured.
The difference (if any) between capturing value types vs. reference types.
And whether there is any boxing occurring with respect to value types.
My preference would be for an answer in terms of values and pointers (closer to the heart of what happens internally), though I will accept a clear answer involving values and references as well.
Is tricky. Will come onto it in a minute.
There's no difference - in both cases, it's the variable itself which is captured.
Nope, no boxing occurs.
It's probably easiest to demonstrate how the capturing works via an example...
Here's some code using a lambda expression which captures a single variable:
using System;
class Test
{
static void Main()
{
Action action = CreateShowAndIncrementAction();
action();
action();
}
static Action CreateShowAndIncrementAction()
{
Random rng = new Random();
int counter = rng.Next(10);
Console.WriteLine("Initial value for counter: {0}", counter);
return () =>
{
Console.WriteLine(counter);
counter++;
};
}
}
Now here's what the compiler's doing for you - except that it would use "unspeakable" names which couldn't really occur in C#.
using System;
class Test
{
static void Main()
{
Action action = CreateShowAndIncrementAction();
action();
action();
}
static Action CreateShowAndIncrementAction()
{
ActionHelper helper = new ActionHelper();
Random rng = new Random();
helper.counter = rng.Next(10);
Console.WriteLine("Initial value for counter: {0}", helper.counter);
// Converts method group to a delegate, whose target will be a
// reference to the instance of ActionHelper
return helper.DoAction;
}
class ActionHelper
{
// Just for simplicity, make it public. I don't know if the
// C# compiler really does.
public int counter;
public void DoAction()
{
Console.WriteLine(counter);
counter++;
}
}
}
If you capture variables declared in a loop, you'd end up with a new instance of ActionHelper for each iteration of the loop - so you'd effectively capture different "instances" of the variables.
It gets more complicated when you capture variables from different scopes... let me know if you really want that sort of level of detail, or you could just write some code, decompile it in Reflector and follow it through :)
Note how:
There's no boxing involved
There are no pointers involved, or any other unsafe code
EDIT: Here's an example of two delegates sharing a variable. One delegate shows the current value of counter, the other increments it:
using System;
class Program
{
static void Main(string[] args)
{
var tuple = CreateShowAndIncrementActions();
var show = tuple.Item1;
var increment = tuple.Item2;
show(); // Prints 0
show(); // Still prints 0
increment();
show(); // Now prints 1
}
static Tuple<Action, Action> CreateShowAndIncrementActions()
{
int counter = 0;
Action show = () => { Console.WriteLine(counter); };
Action increment = () => { counter++; };
return Tuple.Create(show, increment);
}
}
... and the expansion:
using System;
class Program
{
static void Main(string[] args)
{
var tuple = CreateShowAndIncrementActions();
var show = tuple.Item1;
var increment = tuple.Item2;
show(); // Prints 0
show(); // Still prints 0
increment();
show(); // Now prints 1
}
static Tuple<Action, Action> CreateShowAndIncrementActions()
{
ActionHelper helper = new ActionHelper();
helper.counter = 0;
Action show = helper.Show;
Action increment = helper.Increment;
return Tuple.Create(show, increment);
}
class ActionHelper
{
public int counter;
public void Show()
{
Console.WriteLine(counter);
}
public void Increment()
{
counter++;
}
}
}

Categories

Resources