This question already has answers here:
In c#, why can't lambdas have extensions?
(2 answers)
Closed 6 years ago.
On the way home I had an idea: create Func/Action extensions which would allow some nice syntactic sugar in c#.
Theoretical example... create an extension for various permutations of Func/Action which allow you to time the method's execution.
As I arrived home and tried an example, I found this is not possibly. I believe it is a shortcoming/inconsistency in c#. Delegates and methods are one in the same (in theory).
public static class Extensions
{
public static void Time(this Action action)
{
// Logic to time the action
action();
}
}
public class Example
{
public void Main()
{
Action action = RunApp;
Action actionLambda = () => { };
Action actionDelegate = delegate () { };
Extensions.Time(RunApp); // Works
Extensions.Time(() => { }); // Works
Extensions.Time(delegate() { }); // Works
Extensions.Time(action); // Works
Extensions.Time(actionLambda); // Works
Extensions.Time(actionDelegate); // Works
action.Time(); // Works
actionLambda.Time(); // Works
actionDelegate.Time(); // Works
((Action) RunApp).Time(); // Works
((Action) delegate () { }).Time(); // Works
((Action) (() => { })).Time(); // Works
// These should all be the same!
RunApp.Time(); // No good: "Example.RunApp() is a method which is not valid in the given context"
() => { }.Time(); // No good: Operator '.' cannot be applied to operand of type 'lambda expression'"
(() => { }).Time(); // No good: Operator '.' cannot be applied to operand of type 'lambda expression'"
delegate() { }.Time(); // No good: "Operator '.' cannot be applied operand of the type 'anonymous method'"
}
public void RunApp()
{
// Stuff...
}
}
I understand Func/Action are newer additions to c# compared to delegates and method groups, but why can they all not act the same?
Action just nicely encapsulates delegates in a simple way without having to explicitly declare your delegates. In C# delegate is the language mechanism for capturing a method as a type. A type is what you need to create an extension method on.... so, simplifying back to delegates...
public static class Extensions
{
public delegate void Del();
public static void Time(this Del action)
{
// Logic to time the action
action();
}
}
class Program
{
static void Main(string[] args)
{
((Extensions.Del)(() => { })).Time();
}
}
the language won't automatically cast Methods to Del, you need to explicitly do so. Methods themselves aren't a type, delegates are the mechanism to capture them. Fundamentally, in c#, delegate is not the same as method. It's C#s solution to having typesafe pointers to methods.
Another thing to keep in mind is you can do :-
public static class Extensions
{
public delegate void Del();
public delegate void Del2();
public static void Time(this Del action)
{
// Logic to time the action
action();
}
public static void Time(this Del2 action)
{
// Logic to time the action
action();
}
public static void Time(this Action action)
{
// Logic to time the action
action();
}
}
class Program
{
static void Main(string[] args)
{
((Extensions.Del)(() => { })).Time();
((Extensions.Del2)(() => { })).Time();
((Action)(() => { })).Time();
(() => { })).Time(); // no way to know what type this should be coerced to
}
}
Now your methods could be captured as many different types.
Related
I want to make a function to run stuff in a throw-away thread... aka keep executing stuff without waiting for the function in the line before it to excute.
So i made a little function here...
public static object Do(System.Action Method)
{
object ret;
System.Threading.Thread t = new System.Threading.Thread(() =>
{ret = Method(); });
t.SetApartmentState(System.Threading.ApartmentState.STA);
t.Start();
return ret;
}
Looks simple... there is only one problem... i get the following errors
Cannot implicitly convert type 'void' to 'object'
Use of unassigned local variable 'ret'
I don't care about the second because it will fix itself if i just fix the first... but i don't seem to find a solution for the first...
In short:
All i want is to get the return value of the function chosen aka...
I want the following code to work:
string TEST = Do(() => Console.ReadKey()).ToString();
But the method itself is broken.
Action delegate does not return a value.
Use Func<object> to return object from a passed function.
Also in this case the variable will be most likely returned before the function completes.
I recommend using async/await combination instead. In order for your construction to work you would have do something like this:
public static async Task<object> Do(Func<object> Method)
{
object ret = null;
await Task.Run(
() =>
{
ret = Method();
});
return ret;
}
Which boils down to:
public static async Task<object> Do(Func<object> Method)
{
return Task.Run(Method);
}
Example code:
class Program
{
static AutoResetEvent MyThreadCompletedEvent = new AutoResetEvent(false);
static async void MyThread()
{
Console.WriteLine((await MyClass<ConsoleKeyInfo>.Do(Console.ReadKey)).ToString());
MyThreadCompletedEvent.Set();
}
static void Main(string[] args)
{
Task.Run(() => MyThread());
// Do stuff
// Ensure to wait for MyThread to complete
MyThreadCompletedEvent.WaitOne();
}
}
public static class MyClass<T>
{
public static async Task<object> Do(Func<T> Method)
{
return await Task.Run(Method);
}
}
Instead of creating new thread you could do:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(MyClass<ConsoleKeyInfo>.Do(Console.ReadKey));
}
}
public static class MyClass<T>
{
public static object Do(Func<T> Method)
{
return Method();
}
}
From your title:
How do i get return value of action running in a thread in C#?
You can't. If the thread is still running, the "return value" has not yet been computed. It is not available to return, even if you used the correct Func<T> instead of Action<T>.
In other words, the laws of physics in our universe as we currently know them do not allow for retrieving information from the future.
I want the following code to work:
string TEST = Do(() => Console.ReadKey()).ToString();
Assuming you meant TEST to have the value of the pressed key, then you have to wait for the key to be pressed. The same thing would be obtained with:
string TEST = Console.ReadKey().ToString();
(though you probably would want to use the .KeyChar property...)
Since I can define an Action as
Action a = async () => { };
Can I somehow determine (at run time) whether the action a is async or not?
No - at least not sensibly. async is just a source code annotation to tell the C# compiler that you really want an asynchronous function/anonymous function.
You could fetch the MethodInfo for the delegate and check whether it has an appropriate attribute applied to it. I personally wouldn't though - the need to know is a design smell. In particular, consider what would happen if you refactored most of the code out of the lambda expression into another method, then used:
Action a = () => CallMethodAsync();
At that point you don't have an async lambda, but the semantics would be the same. Why would you want any code using the delegate to behave differently?
EDIT: This code appears to work, but I would strongly recommend against it:
using System;
using System.Runtime.CompilerServices;
class Test
{
static void Main()
{
Console.WriteLine(IsThisAsync(() => {})); // False
Console.WriteLine(IsThisAsync(async () => {})); // True
}
static bool IsThisAsync(Action action)
{
return action.Method.IsDefined(typeof(AsyncStateMachineAttribute),
false);
}
}
Of course, You can do that.
private static bool IsAsyncAppliedToDelegate(Delegate d)
{
return d.Method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null;
}
If you're looking to build some logic, based on whether a sync or async lanbda has been passed to your method - just introduce overloads.
public void MyMethod(Action action)
{
DoStuff();
}
public void MyMethod(Func<Task> asyncAction)
{
DoOtherStuff();
}
I have a method that I call multiple times, but each time a different method with a different signature is called from inside.
public void MethodOne()
{
//some stuff
*MethodCall();
//some stuff
}
So MethodOne is called multiple times, each time with a different *MethodCall(). What I'm trying to do is something like this :
public void MethodOne(Func<> MethodCall)
{
//some stuff
*MethodCall;
//some stuff
}
but the Methods that are called each have a different return type and different parameters. Is there a way to do this using Functors? If not, how would I go about doing this?
Thank you!
You best bet would be to use the non-generic Action type (or MethodInvoker would be the same), i.e.
public void MethodOne(Action callback)
{
//some stuff
if(callback != null) callback();
//some stuff
}
From this you can call any method by wrapping it at the caller, i.e.
MethodOne(SimpleMethod); // SimpleMethod has no parameters and returns void
MethodOne(() => MoreComplexMethod(1, "abc")); // this one returns void
MethodOne(() => { MethodThatReturnsSomething(12); }); // anything you like
etc
You cannot call a function which requires parameters without supplying them, so the answer is "no, not possible"
Also, maybe you want the following:
void MethodOne(Action a)
{
// some stuff
a();
// some stuff
}
... // somewhere in the code
MethodOne((Action)(() => { DoSomethingOther(1, 2, 3); }));
MethodOne((Action)(() => { DoSomethingEvenDifferent(1, 2, 3, 4, 5); }));
Every delegate in .Net is an instance of a class derived from Delegate. So if you really wish to pass 'any' delegate to a method, you can pass it as Delegate
To invoke it, you need to use its DynamicInvoke method.
public void MethodOne(Delegate MethodCall)
{
//some stuff
//Assuming you now have the required parameters
//or add params object[] args to the signature of this method
object res = MethodCall.DynamicInvoke(args); //args is object[] representing the parameters
//some stuff
}
But this is not recommended as DynamicInvoke is slow and it does not offer any compile time safety. Probably you should revisit your design.
This is basically not possible. You could make MethodOne generic for the return type, and use a lambda that closes over its outside block instead of parameters:
static void Main(string[] args)
{
int parameterSubst = 1;
int result = MethodOne<int>(() => parameterSubst);
string result2 = MethodOne<string>(() =>
{
string s = parameterSubst.ToString();
s += "foo";
return s;
});
}
static T MethodOne<T>(Func<T> function)
{
return function();
}
As you can see, parameterSubst is used in the passed Func<T>s, but not as a parameter.
I'm trying to pass a reference to a function as a parameter
It's hard to explain
I'll write some example pseudo code
(calling function)
function(hello());
function(pass)
{
if this = 0 then pass
else
}
hello()
{
do something here
}
Sorry if it does not make much sense
But I'm trying to reduce used code and I thought this would be a good idea.
How can I do this in C#?
You can pass code to a method by using delegates, for example, the Action delegate:
void MyFunction(Action action)
{
if (something == 0)
{
action();
}
}
void Hello()
{
// do something here
}
Usage:
MyFunction(Hello);
I'm trying to pass a reference to a function as a parameter
It's hard to explain
It may be hard to explain, but it is very easy to implement: the code below calls MyFunction passing it a parameterized piece of code as a parameter.
static void MyFunction(Action<string> doSomething) {
doSomething("world");
}
static void Main(string[] args) {
MyFunction((name) => {
Console.WriteLine("Hello, {0}!", name);
});
}
You can use delegate types provided by the system (Action and Func) or write your own.
Here is an example:
using System;
public class Example
{
public void Method1(Action hello)
{
// Call passed action.
hello();
}
public void Method2()
{
// Do something here
}
public void Method3()
{
Method1(Method2);
}
}
I am using the following methods:
public void M1(Int32 a)
{
// acquire MyMutex
DoSomething(a);
// release MyMutex
}
and
public void M2(String s, String t)
{
// acquire MyMutex
DoSomethingElse(s, t);
// release MyMutex
}
From what I have found so far it seems that it is not possible to use a single delegate for two methods with different signatures.
Are there any other alternatives to write something like this:
public void UsingMutex(...)
{
// acquire MyMutex
...
// release MyMutex
}
UsingMutex(M1);
UsingMutex(M2);
All I can think for the moment is to use two delegates and a boolean flag to know which delegate to call, but it is not a long term solution.
It is possible to combine generics with delegates? And if so, do you have some links for any kind of documentation?
Environment: C# 2.0
Absolutely you can mix delegates with generics. In 2.0, Predicate<T> etc are good examples of this, but you must have the same number of args. In this scenario, perhaps an option is to use captures to include the args in the delegate?
i.e.
public delegate void Action();
static void Main()
{
DoStuff(delegate {Foo(5);});
DoStuff(delegate {Bar("abc","def");});
}
static void DoStuff(Action action)
{
action();
}
static void Foo(int i)
{
Console.WriteLine(i);
}
static void Bar(string s, string t)
{
Console.WriteLine(s+t);
}
Note that Action is defined for you in .NET 3.5, but you can re-declare it for 2.0 purposes ;-p
Note that the anonymous method (delegate {...}) can also be parameterised:
static void Main()
{
DoStuff(delegate (string s) {Foo(5);});
DoStuff(delegate (string s) {Bar(s,"def");});
}
static void DoStuff(Action<string> action)
{
action("abc");
}
static void Foo(int i)
{
Console.WriteLine(i);
}
static void Bar(string s, string t)
{
Console.WriteLine(s+t);
}
Finally, C# 3.0 makes this all a lot easier and prettier with "lambdas", but that is another topic ;-p
Yes, it's possible to combine generics with delegates.
public delegate void Action<T>(T x);
public delegate void Action<T,U>(T x, U y);
public void UsingMutex<T>(Action<T> x, T t) {
// acquire mutex...
x(t);
// release mutex...
}
public void UsingMutex<T,U>(Action<T,U> x, T t, U u) {
// acquire mutex...
x(t, u);
// release mutex...
}
But you still have to handle different number of parameters using overloads.
If you look at the Func<T> and Action<T> delegates in the framework, you'll see that they define a number of similar delegates with different number of parameters. You can use generics, but that doesn't solve the number of arguments issue you're talking about.