Task.Run how to write it with action and ref variable name - c#

I am standing for a "little" syntax problem and cannt figure out how to correctly write what I desire.
I have the following method:
public void DoSomeMagic(string foo, ref string bar)
{
//DoSomeMagic...
}
Now I would like to offload this code inside a Task.Run I would normally write the following:
public async void Button_Click(object sender, EventArgs args)
{
string foo = "Hello Foo";
string bar = "Hello Bar";
await Task.Run(() => DoSomeMagic(foo, ref bar));
}
This doesn't compile telling me: "Cannot use 'ref' or 'out' parameter 'bar' inside an anonymous method body"
So I thought why even do the () => since I am just calling the method and I could reduce it to this:
Task.Run(DoSomeMagic(foo, ref bar));
This again doesn't compile telling me: Cannot resolve method 'Run(void)', candidates are: Run(Action) and Run(Func)
So again no problem Visual Studio your demand is my command.
And changed the code to this:
Task.Run((Action)DoSomeMagic(foo, ref bar));
Again doesn't compile telling me: Cannot cast expression of type 'void' to type 'Action',
Okay this starts getting tricky...
I than tried to instead of returning void I will just try int and cast to Func
giving me the error: Cannot cast expression of type 'int' to type 'Func'
Saw that one coming but I thought lets give it a try:
So I tried the following approach:
public Action CallDoSomeMagic(string foo, ref string bar)
{
//DoSomeMagic...
return new Action(() => DoSomeMagic(foo, ref bar));
}
Task.Run(CallDoSomeMagic);
But this again gives me the message "Cannot use 'ref' or 'out' parameter 'bar' inside an anonymous method body"
Since my headache is increasing with every try, I thought you guys can help me out.
Is it even possible?

As the message says: you can't do that.
You could take a copy of the parameter value, and capture that, for example:
public Action CallDoSomeMagic(string foo, ref string bar)
{
var snapshot = bar;
return new Action(() => DoSomeMagic(foo, ref snapshot));
}
But note that updates to snapshot are not visible outside the caller via bar.
The reasons for this are two-fold:
Firstly, captured variables used on a lambda become fields on a compiler-generated context class. This works fine for non-ref/out parameters, as they already have a copy semantic. So in the case of my snapshot example, this is actually:
var ctx = new CompilerGeneratedContextClassWithHorribleName();
ctx.foo = foo;
ctx.snapshot = bar;
return new Action(ctx.CompilerGeneratedMethod);
where CompilerGeneratedMethod is:
DoSomeMagic(foo, ref snapshot);
this isn't possible for refs, as you'd essentially need the field to be a reference to a string-reference, which is... messy.
But more importantly: consider the lifetime of the caller. This could be:
void SomeMethod() {
string s = "abc";
CallDoSomeMagic("def", ref s);
}
Note in particular that the code needs to work even if the delegate is invoked much later - as indeed we might expect it to in your case since it involves Task and async. Now: if SomeMethod has exited: where is that reference to a string-reference pointing? Hint: it is just an arbitrary location on the stack, now out of scope.
Just to give a simpler workaround: instead of passing ref string bar, consider passing SomeType obj, where obj.Bar is the string you want; i.e.
public Action CallDoSomeMagic(string foo, SomeType obj)
{
return new Action(() => DoSomeMagic(foo, obj));
}
public void DoSomeMagic(string foo, SomeType obj)
{
// read and write obj.Bar here
}
Note you could also move foo to obj.Foo if you wanted.

Related

Use Action instead of Func

This is from the factory pattern, where a property is used to get an instance via Create:
public class Dialer
{
public static Func<Dialer> Create;
public bool MakeCall(string number) ...
public Dialer(IDialer impl) { ... }
}
Then a lambda expression is assigned to the property delegate in the platform-specific project with
Dialer.Create = () => new Dialer(new PhoneDialeriOS());
and to get an instance in the platform-independent project I use
this.dialer = Dialer.Create();
Now I'm looking to use
public static Action<Dialer> Create;
If I get this right, the assignment now is
Dialer.Create = (d) => new Dialer(new PhoneDialeriOS());
but how do I get an instance?
this.dialer = // ?
By using this.dialer = Dialer.Create(); I get
Error CS7036 There is no argument given that corresponds to the required formal parameter 'obj' of 'Action'
But it doesn't make sense to pass an instance of PhoneDialeriOS here, because there is no access to it in the platform-independent code. I think the example I'm regarding to is misleading or I'm missing something.
Action<Dialer> is a a delegate that receives a Dialer instance, and returns void. It's an Action, after all. If you want it to return a value (and get an argument), you need to use Func<Dialer, Dialer> instead.
The following could be possible usages
var specific_dialer = new Dialer(new PhoneDialeriOS());
var defualt_dialer = Dialer.Create();
Edit
Of course you can do something like
Dialer.Create = () => new Dialer(new PhoneDialerAndroid());
without the (likely a wrong copy/paste) line with the Action

TargetParameterCountException: Parameter count mismatch on invoke - delegate

I have the following code (removed unrelated)
//top of class declaration
private delegate void UpdateFormElements(string status, bool addEmptyRow);
//inside a function in my class
if(lboImages.InvokeRequired)
{
lboImages.Invoke((UpdateFormElements)delegate { UpdateListBox("some text", true); });
}
private void UpdateListBox(string line, bool addEmptyRow)
{
lboImages.Items.Add(line);
if (addEmptyRow)
{
lboImages.Items.Add("");
}
}
Basically I'm trying to pass two parameters to the UpdateListBox function to test whether to add an empty line or not to my listbox, but I am getting the error in the title. I have tried putting the two values in an object[] but it doesn't seem to change anything as I still get the error.
I'm still new to using threads so not really sure where I'm going wrong here.
It's not clear why you're trying to use an anonymous method here. The problem is that you're creating a delegate type with two parameters, but you're not passing arguments (values for those parameters) into Invoke.
I suspect you just want:
lboImages.Invoke((UpdateFormElements) UpdateListBox, "some text", true));
That uses a method group conversion to create an UpdateFormElements delegate, and provides it the two arguments it needs.
Alternatively, you could just use a lambda expression:
MethodInvoker invoker = () => UpdateListBox(line, addEmptyRow);
lboImages.Invoke(invoker);

Assigning code to a variable

Is it possible to make a variable, and assign a line of code to it, such as:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... so when I use the variable, it will execute the line of code.
You could assign it to an Action like this:
var ButtonClicked = new Action(() => MessageBox.Show("hi"));
Then call it:
ButtonClicked();
For completeness (in regards to the various comments)...
As Erik stated, you could execute multiple lines of code:
var ButtonClicked = new Action(() =>
{
MessageBox.Show("hi");
MessageBox.Show("something else"); // something more useful than another popup ;)
});
As Tim stated, you could omit the Action keyword
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// multiple lines of code
};
To address KRyan's comment, regarding the empty parentheses, that represents the list of parameters you want to be able to send to the Action (in this case, none).
If, for instance, you wanted to specify the message to show, you could add "message" as a parameter (note that I changed Action to Action<string> in order to specify a single string parameter):
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
In your case, you want to use a delegate.
Let's see how a delegate works and how we can get to an easier form by understanding its concept:
// Create a normal function
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();
You see, the delegate takes the form of a normal function but without any arguments (It could take any amount of arguments just like any other method, but for the sake of simplicity, it doesn't).
Now, let's use what we have; we will define the delegate just as we define any other variable:
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
We basically created a new variable called ButtonClicked, that has a type of ButtonClick (which is a delegate) and that when used, will execute the method in the OnButtonClick() method.
To use it we simply call: ButtonClicked();
So the whole code would be:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
From here, we can move to lambda expressions and see how they could be useful in your situation:
There are many delegates already defined by .NET libraries, with some like Action, which do not accept any parameter and does no return a value. It is defined as public delegate void Action();
You can always use it to your needs instead of the need of defining a new delegate every time. In the previous context for example, you could had just written
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
which would had done the same.
Now that you saw different ways of how to use delegates, let's use our first lambda expression. Lambda expressions are anonymous functions; so, they are normal functions but without a name. They are of those forms:
x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");
In our case, we do not have any parameters so we will use the last expression. We can use this just as the OnButtonClick function, but we get the advantage of not having a named function. We can instead do something like this:
Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );
or even easier,
Action ButtonClicked = () => MessageBox.Show("Hello World!");
then simply call ButtonClicked(); Of course you can also have multi-lines of code, but I do not want to confuse you more. It would look like this though:
Action ButtonClicked = () =>
{
MessageBox.Show("Hello World!");
};
ButtonClicked();
You could also play around, for example, you can execute a function like this:
new Action(() => MessageBox.Show("Hello World!"))();
Sorry for the long post, hope it was not too confusing :)
EDIT: I forgot to mention that an alternate form which, even though not often used, could make lambda expressions easier to understand:
new Action(delegate() {
Console.WriteLine("I am parameterless");
})();
Also, using generics:
// Defines a delegate that has one parameter of type string. You could pass as many parameters as you want.
new Action<string>(delegate(string x) {
Console.WriteLine(x);
})("I am a string parameter!");
In turn you could use lambda expressions, but you do not need (but might in some cases) to define the type of the parameter, for example, the code above could simply be written as:
new Action<string>(x => {
Console.WriteLine(x);
})("I am a string parameter!");
or:
new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");
EDIT2:
Action<string> is a representation of public void delegate Action(string obj);
Action<string,string> is a representation of public void delegate Action(string obj, string obj2);
In general, Action<T> is a representation of public void delegate Action<T>(T obj);
EDIT3:
I know the post has been here for a while, but I think this is really cool to not mention:
You can do this, which is mostly related to your question:
dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");
or simply:
Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
The Lazy class is specifically designed to represent a value that won't be computed until you ask for it. You construct it by providing a method that defines how it should be constructed, but it will handle executing that method no more than once (even in the face of multiple threads requesting the value) and simply returning the already constructed value for any additional requests:
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
The way I'm reading your question, this is in the context of GUI controls?
If this is in WPF, take a look at the "right" way to handle commands from controls:
http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
...but that can be a pain and overkill. For a simpler general case, you might be looking for an event handler, like:
myButton.Click += (o, e) => MessageBox.Show("Hello, World!");
That event handler can be handled a variety of ways. The above example uses an anonymous function, but you could also do:
Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);
...just like you were asking, with a function (or here, "Action", since it returns void) assigned as a variable.
You can assign C# code to a variable, compiling it at runtime and run the code:
Write your code:
// Assign C# code to the code variable.
string code = #"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ #"
}
}
}
";
Create the provider and parameters of the compiler:
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Define parameters of the compiler:
// Reference to System.Drawing library
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
// True - memory generation, false - external file generation
parameters.GenerateInMemory = true;
// True - exe file generation, false - dll file generation
parameters.GenerateExecutable = true;
Compile assembly:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
Check errors:
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Get assembly, type and the Main method:
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
Run it:
main.Invoke(null, null);
Reference:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime

C# compiler oddity with delegate constructors

Based on the following question, I found some odd behaviour of the c# compiler.
The following is valid C#:
static void K() {}
static void Main()
{
var k = new Action(new Action(new Action(K))));
}
What I do find strange is the compiler 'deconstructing' the passed delegate.
The ILSpy output is as follows:
new Action(new Action(new Action(null, ldftn(K)), ldftn(Invoke)).Invoke);
As one can see, it automatically decides to use the Invoke method of the delegate. But why?
As it is, the code is unclear. Do we have a triply-wrapped delegate (actual) or is the inner delegate just 'copied' to the outer ones (my initial thought).
Surely if the intent was like the compiler emitted the code, one should have written:
var k = new Action(new Action(new Action(K).Invoke).Invoke);
Similar to the decompiled code.
Can anyone justify the reason for this 'surprising' transformation?
Update:
I can only think of one possible use-case for this; delegate type conversion. Eg:
delegate void Baz();
delegate void Bar();
...
var k = new Baz(new Bar( new Action (K)));
Perhaps the compiler should emit a warning if the same delegate types are used.
The spec (section 7.6.10.5) says:
The new delegate instance is initialized with the same invocation list as the delegate instance given by E.
Now suppose the compiler translated it to something similar to your suggestion of:
new Action( a.Target, a.Method)
That would only ever create a delegate with an invocation list of a single method call. For a multi-cast delegate, it would violate the spec.
Sample code:
using System;
class Program
{
static void Main(string[] args)
{
Action first = () => Console.WriteLine("First");
Action second = () => Console.WriteLine("Second");
Action both = first + second;
Action wrapped1 =
(Action) Delegate.CreateDelegate(typeof(Action),
both.Target, both.Method);
Action wrapped2 = new Action(both);
Console.WriteLine("Calling wrapped1:");
wrapped1();
Console.WriteLine("Calling wrapped2:");
wrapped2();
}
}
Output:
Calling wrapped1:
Second
Calling wrapped2:
First
Second
As you can see, the real behaviour of the compiler matches the spec - your suggested behaviour doesn't.
This is partly due to the somewhat odd "sometimes single-cast, sometimes multi-cast" nature of Delegate, of course...
When you try to treat a delegate as a method, the compiler actually uses the delegate's Invoke() method. So, for example, the two lines below compile to the exact same IL (both call Invoke()):
k();
k.Invoke();
I assume the oddity you're seeing is a consequence of this. The delegate constructor expects a method (or rather, a method group), but it gets a delegate instead. So it treats it as a method and uses the Invoke() method.
As for the meaning, it is delegate that calls delegate that calls the actual method. You can verify this yourself by accessing the delegate's Method and Target properties. In the case of the outer-most delegate, Method is Action.Invoke and Target the inner delegate.
delegate is a class
Action delegate has a constructor like so
public extern Action(object #object, IntPtr method);
Since K is a static method there is no need to pass object to inner most action instance as first argument and hence it passes null
Since second argument is pointer to function therefore it passes pointer of K method using ldftn function
for the remaining Action instances the object is passed is inner Action and the second parameter is the Invoke method since when you call a delegate you're actually calling the Invoke method
Summary
var action = new Action(K) => Action action = new Action(null, ldftn(K))
new Action(action) => new Action(action, ldftn(Action.Invoke))
I hope this explains what is happening?

Ref C# - new assignment in foo, propagates to other functions using same reference?

My basic question is asking if I change the reference of a ref in one method is it reflected in the other method (like double pointers in C++)?
method()
{
referenceTypeInt t = new t(1);
asyncCall foo(ref t);
bar(ref t);
}
foo(ref a)
{
a = new t(3);
}
bar (ref a)
{
wait for 10 seconds/until foo finishes;
Console.print ("t is" t.ToString())
}
The above is rough Pseudoish code, but would t be 3 above?
That's how ref works, in general.
However, there may be one point here that's bad. I'm not sure if this:
asyncCall foo(ref t);
Was meant to be pseudo code for the new Async CTP (in which case, it should be await foo(ref t);). If that was meant to be an async method call using the new async/await syntax, this won't work. ref and out parameters are not supported in async methods (similar to how they are not supported in iterators).
Yes, that's the point of ref. It indicates that the parameter should be treated as an alias to the variable, so assigning to it will alter the the variable itself. Since you ref again in bar, you have another alias, so the change reflected in the output.

Categories