简体   繁体   中英

How do I actually write/end an async method in c#?

I get that I need to await thing in an async marked method to make it asynchronous, but I don't get how to actually end the hole it makes.

static async void Example()
{
    int t = await getIntAsync();
    WriteLine($"computer: {t}");
}

Since getIntAsync is marked async I have to await in that method or I get a warning. But oh no in the method I await on in getIntAsync I have to mark that as aasync, then unless there is an await in there I get a warning. And so on and so forth to infinity it seems. How do I just make it stop?

I've had a few people tell me to put

await Task.Delay(1000);  

In my code, but I know the answer can't be as smelly as putting a delay of a second in all my production code.

A couple others said a task method to end it such as

static Task task()
{
  //code
}

But unless I mark that async it throws the same warning that got me into this confusion. I know

static Task task()
{
  //code
  return Task.FromResult(0);
}

Technically it works, but again that seems too much of a code smell to have all over production.

I just don't get it...

EDIT: Because it was asked for. I know its a very trivial method, but its also just one I'm using for practice.

    static async Task<int> getIntAsync()
    {

        Console.Write("Enter the number: ");
        int n = int.Parse(Console.ReadLine());
        return n;

    }

What is confusing here is that you don't really do something asynchronous . Console.ReadLine() is a synchronous method. Simply typing async or await somewhere does not magically make this asynchronous.

Since this code is only for testing and learning, one way to make it asynchronous is to put it on another thread using Task.Run() (I would not suggest this for many cases in production code):

static Task<int> getIntAsync()
{
    Console.Write("Enter the number: ");
    return Task.Run(() => int.Parse(Console.ReadLine());
}

There is no async keyword needed here as you are not awaiting something. You just return a Task<int> that is completed when the user has entered a value and that value was parsed.

And your Example() method then works like that:

static async void Example()
{
    int t = await getIntAsync();
    WriteLine($"computer: {t}");
}

When the await is hit, the control flow is returned to the caller and the rest of this method (the assignment to t and the call to Console.WriteLine() ) are scheduled as a continuation that is executed when the Task<int> returned by getIntAsync() has finished.

The following is needed (async keyword is required and so is the await, it's simply best practice):

  1. The Async keyword
  2. The Await keyword
  3. Some process that you want to work independently while the asynchorous process runs.
  4. Typically, you return value comes from your await task (which should fill in the end hole).

Here is example using a StreamReader,

async Task<string> GetStringFromReaderAsync()
{
  Streamreader sr = new StreamReader("filename.txt");

     Task<string> getStringTask = sr.ReadLineAsync("filepath");

    //Allow user to continue with some other work.
     DoFileLookup();

  string result = await sr.getStringTask();

  return result.ToString();

}

More information here: https://msdn.microsoft.com/en-us/library/system.io.streamreader.readlineasync(v=vs.110).aspx

More about Async and Await: https://msdn.microsoft.com/en-us/library/mt674882.aspx

 static async Task<int> getIntAsync() { Console.Write("Enter the number: "); int n = int.Parse(Console.ReadLine()); return n; } 

This will run synchronously as there is no await statement And no awaited call to an async method

the general idea is this

   public async Task<int> ExecuteAsync() //Method return type is Task<int>
   {
      // Error: return type is not int. Return type is Task<int>
      return db.SaveChangesAsync(); 

      // OK: returns a task handle that you can await on in you code that called ExecuteAsync()
      // you thread continues processing in your calling function until you try to read the value from this return statement.
      return await db.SaveChangesAsync(); 

      // Ok. Your Thread leaves here and returns when result available.
      // no further Processing done in calling function
      return db.SaveChangesAsync().Result; 

      // Ok. This is not required in this case, 
      // but if you have an async method that has multiple return points, 
      // and one of them does not depend on an async method, you can wrap
      // the output e.g. return await Task.FromResult(0); 
      return await Task.FromResult(db.SaveChangesAsync().Result); 

      return 0; //also ok.
   }

Adding on to the other answer below.

static async Task<int> GetIntAsync()
{
    Console.Write("Enter the number: ");
    return await Task.Run(() => int.Parse("1"));
}

This approach makes something that runs synchronously to be wrapped in a task. However you should never do this (unless of course you know what you are doing) as this spawns another thread. One use case where I have used this is for offloading in webservers but otherwise generally its a bad idea. So while you may have begin with the intention of have maximum utilization of a single thread, you have now ended up with two thread working.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM