Overload resolution and async await - c#

Below code gives error CS0121,
The call is ambiguous between the following methods or properties: 'RunTask(System.Func<System.Threading.Tasks.Task>)' and 'RunTask(System.Action)'
static void RunTask(Func<Task> intTask)
{
}
static void RunTask(Action voidTask)
{
}
static async Task DoAsyncTask()
{
await Task.Delay(500);
}
public static void Main(string[] args)
{
var asyncTask = new Func<Task>(DoAsyncTask);
RunTask(DoAsyncTask);
}
But below code can compile
static void RunTask(Func<Task> intTask)
{
}
static void RunTask(Action voidTask)
{
}
static async Task DoAsyncTask()
{
await Task.Delay(500);
}
public static void Main(string[] args)
{
var asyncTask = new Func<Task>(DoAsyncTask);
RunTask(asyncTask);
}
Why so?

The C# compiler does not take return type of a delegate into account when trying to decide the best overloaded method that takes a delegate.
Also see this question

Related

How to get Attribute value of calling method

I would like to dynamically get the value of the attribute on method, which could be anywhere in the calling hierarchy.
Now I have found the solution using StackTrace's FrameCount and GetFrame. But it's not dynamic
Rollback.cs
namespace AnotationTest
{
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
class RollbackAttribute: Attribute
{
public Guid RollbackGuid { get; set; }
public RollbackAttribute()
{
RollbackGuid = Guid.NewGuid();
}
}
}
Program.cs
class Program
{
static void Main(string[] args)
{
Test();
}
[RollbackAttribute]
public static void Test()
{
Test1();
}
public static void Test1()
{
Test2();
}
public static void Test2()
{
Test3();
}
public static void Test3()
{
Test4();
}
public static void Test4()
{
var framecount = new StackTrace().FrameCount;
System.Reflection.MethodBase method = new StackTrace().GetFrame(framecount-2).GetMethod();
RollbackAttribute rollback = (RollbackAttribute)method.GetCustomAttributes(typeof(RollbackAttribute), true)[0];
}
}
I would like to have a solution to get the attribute value from the Test4 method. But without using StackTrace which is used now. Thank you for any help.
What you want to use is CallContext and its Set/GetLogicalData methods that serves the purpose of traversing data from caller to "callee" without the need to use method parameters or attributes.
class Program
{
static void Main(string[] args)
{
CallContext.LogicalSetData("rollbackGuid", Guid.NewGuid());
Test();
Console.ReadKey();
}
public static void Test()
{
Test1();
}
//[RetryOnExceptionAttribute]
public static void Test1()
{
Test2();
}
public static void Test2()
{
Test3();
}
public static void Test3()
{
Console.WriteLine($"Current thread id: {Thread.CurrentThread.ManagedThreadId}");
Task.Run((() => { Test4(); }));
}
public static void Test4()
{
Console.WriteLine($"Current thread id: {Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"Rollback guid: {Rollback.CurrentGuid}");
}
}
static class Rollback
{
public static Guid CurrentGuid => (Guid)CallContext.GetData("rollbackGuid");
}

cannot await method group func delegate

I have a func delegate that is defined as follows,
public enum RunEndStatus
{
Success
}
public class classA
{
Func<object, RunEndStatus> ProcessCalibrationRun { get; set; }
}
Now in an other class lets say classB I am doing something like this,
public class ClassB
{
public void DoSomething()
{
ClassA a = new ClassA();
a.ProcessCalibrationRun = ProcessCalibrationRun;//This is just fine. It won't complain here.
}
public RunEndStatus ProcessCalibrationRun(object obj)
{
//Here I have some piece of code takes so much time. To replicate it,
Thread.Sleep(10000);
}
}
When the DoSomething method is called from somewhere, the application blocks for 10 minutes.So I am trying to fix my problem as follows,
public async Task<RunEndStatus> ProcessCalibrationRun(object obj)
{
await Task.Run(() => { Thread.Sleep(10000)});
return RunEndStatus.Success;
}
I am modifying the call as follows. But it says cannot await method group. Please help how can I await on that method.
public async void DoSomething()
{
ClassA a = new ClassA();
a.ProcessCalibrationRun = await ProcessCalibrationRun; //Here it complains saying cannot await method group.
}
An async signature returns a Task, so your Func will need to as well
public Func<object, Task<RunEndStatus>> ProcessCalibrationRun { get; set; }
Meaning you will not need the async signature in your DoSomething, which should not be async void anyway
public void DoSomething()
{
vara = new ClassA();
a.ProcessCalibrationRun = ProcessCalibrationRun;
}
Then somewhere else (perhaps in ClassA) you can invoke it
public async Task DoSomethingElse()
{
await ProcessCalibrationRun(somethignObject);
}

Task.Run Ambiguous Parameter Overloads

I'm using the Task class in C# and want to pass a predefined method that returns a value and not using lambdas to the Task.Run method.
Here is a console app with the code:
static int ThreadMethod()
{
return 42;
}
static void Main(string[] args)
{
Task<int> t = Task.Run(function:ThreadMethod);
WriteLine(t.Result);
}
However, it is returning this error:
The call is ambiguous between the following methods or properties: 'Task.Run<TResult>(Func<TResult>)' and 'Task.Run(Func<Task>)'
I tried doing this to fix it and got my expected result:
Task<int> t = Task.Run((Func<int>)ThreadMethod);
However, I am not sure if I'm doing it right or are there any better solution?
Fix your .Run argument like in this example. Can be copied and pasted into LinqPad to test.
public static void Main(string[] args)
{
Task<int> t = Task.Run(() => ThreadMethod());
WriteLine(t.Result);
}
public static int ThreadMethod()
{
return 42;
}
If you want to see it as a variable to pass check out below:
public static void Main(string[] args)
{
//Func<int> is saying I want a function with no parameters
//but returns an int. '() =>' this represents a function with
//no parameters. It then points to your defined method ThreadMethod
//Which fits the notions of no parameters and returning an int.
Func<int> threadMethod = () => ThreadMethod();
Task<int> t = Task.Run(threadMethod);
Console.WriteLine(t.Result);
}
public static int ThreadMethod()
{
return 42;
}
Here is the Documentation on Func(T), on the left hand menu you can select the different variations of Func() objects.

C# app fall down when use Task in PCL

I've created PCL Library:
here code:http://dumpz.org/1131545/.
In this PCL I've created an interface and class, that class call an method of this interface with Task.
Next I've added C# Class Library project, added reference to pcl and implemented this interface(http://dumpz.org/1131549/).
After it, I've added ConsoleApp, added reference to PCL and added implemented from C# CLP as a link to files.(http://dumpz.org/1131550/)
namespace PortableClassLibrary1
{
public interface test
{
void test();
}
public class Class1
{
test Test;
public Class1(test Test)
{
this.Test = Test;
}
public Task<bool> Call()
{
return Task.Factory.StartNew(() =>
{
try
{
Test.test();
return true;
}
catch(Exception ex)
{
return false;
}
});
}
}
}
in C# CLP:
class Impl:test
{
public Impl()
{
}
public void test()
{
CookieContainer s = new CookieContainer();
}
}
Console App:
class Program
{
static Class1 s;
static void Main(string[] args)
{
s = new PortableClassLibrary1.Class1(new Impl());
test();
}
static async void test()
{
bool x = await s.Call();
if(x == true)
{
Console.WriteLine("test");
}
else
{
Console.Write("");
}
}
}
But when I call implemented method app fall down.
Please explain me why?
Thank you for your time.
When you await, control is yielded back to the caller. In your app, that means that when you await s.Call(), control yields back to test which is the last method inside Main, which then finishes execution and closes the console app.
What you have to do is explicitly call Wait on the Task
class Program
{
static Class1 s;
static void Main(string[] args)
{
s = new PortableClassLibrary1.Class1(new Impl());
test().Wait();
}
static async Task test()
{
bool x = await s.Call().ConfigureAwait(false);
if(x == true)
{
Console.WriteLine("test");
}
else
{
Console.Write("");
}
}

Async/await: Making method async

I'm trying to do a simple example but I'm not even getting the basics. What's wrong with this code? Imagine Calculate() takes a few seconds.
static void Main(string[] args)
{
int result = await Calculate();
Console.WriteLine(result);
Console.ReadLine();
}
static async Task<int> Calculate()
{
return 1;
}
Simply change your main to:
static void Main(string[] args)
{
int result = Calculate().Result;
Console.WriteLine(result);
Console.ReadLine();
}
As soon as you use the await keyword, the surrounding method must be marked as async which - as others metnioned - is not possible for Main.
Since async methods like Calculate still return good old Task objects, feel free to use the "old" way of dealing with them: using Result to wait for results. Of course this is a blocking operation - but no reason to be non-blocking inside Main, right? ;)
You can do this:
static void Main()
{
WrapMain();
}
static async void WrapMain()
{
int result = await Calculate();
Console.WriteLine(result);
Console.ReadLine();
}
static async Task<int> Calculate()
{
return await Task.Run(() =>
{
return 1;
});
}

Categories