11

I have method with signature I cannot change. It should be

protected override void OnInitialize()

Using Windows 8 Metro API I need to check if file exists and read it, inside this NoSignatureChange method. Using PlainOldCSharp, I would write something like

protected override void OnInitialize()
{
  ...
  try
  {
    var file = folder.OpenFile(fileName);
    fileExists=true;
  }
  catch(FileNotFoundException)
  {
    fileExists=false
  }
}

Remember, in Windows 8 API only way to check if file exists is handling FileNotFoundException Also, in Windows 8 API all FileIO API is async, so I have only file.OpenFileAsync method.

So, the question is: How should I write this code using folder.OpenFileAsync method in Windows 8 API without changing signature of containing method

Community
  • 1
  • 1
Alex Sorokoletov
  • 3,102
  • 2
  • 30
  • 52
  • Oh, and AsTask().Wait() can throw 3 different exceptions itself – Alex Sorokoletov Aug 03 '12 at 21:14
  • Why exactly can't you change the signature of the method? – svick Aug 03 '12 at 21:16
  • It's far better to change the signature. If you're porting a class library of some kind to Metro then guess what? It should be made `async` (in this case, `async Task`, not `async void`). That's the cleanest way to do it. It is *possible* to force Metro to block, but you'll be fighting the platform and APIs the entire way, and you'll definitely endanger the chances of your application being approved for the store. – Stephen Cleary Aug 03 '12 at 21:48
  • There are 3rd party SDK I cannot change. – Alex Sorokoletov Aug 03 '12 at 21:51
  • You're referencing an answer from December (based on the developer preview) to assert your "the only way to check if the file exists". You might want to try the release preview to see if the answer has changed - there have been many changes made since the developer preview. – Larry Osterman Aug 04 '12 at 21:12
  • @LarryOsterman I found that API using RP, and was checking if somebody knows any other ways. Sure, I've checked current classes and members in FileIO namespace. – Alex Sorokoletov Aug 04 '12 at 23:37

2 Answers2

23

You can still make a void method async:

protected async void CannotChangeSignature()
{
    ...
}

Valid return types for an async method are:

  • void
  • Task
  • Task<T>

However, if you want to make it actually block, then you're basically fighting against the platform - the whole point is to avoid blocking.

You say you can't change the signature - but if you're relying on this blocking then you've got to change the way you approach coding.

Ideally you should change the signature to Task<bool>:

protected async Task<bool> CannotChangeSignature()
{
  ...
  try
  {
    await ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
    return true;
  }
  catch(FileNotFoundException)
  {
    return false;
  }
}

EDIT: If you really need a blocking one, you'll just have to call AsTask().Wait(), catch the AggregateException and check whether it contains a FileNotFoundException. It really is pretty horrible though... can you not design around this so that it doesn't need to be blocking? For example, start checking for the file, and show an error (or whatever) if and when you find it doesn't exist.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    That being said, aside from that I wouldn't use 'Cannot' in a method name. I'm not sure if that's against convention or not, but it makes it just that little bit more difficult to understand what's happening at first glance. But that's my humble opinion I guess ;-) – Erik van Brakel Aug 03 '12 at 21:22
  • Jon, thanks for answering. Yes I need it to be blocking, and reason is I using other components in my app and they define interfaces. – Alex Sorokoletov Aug 03 '12 at 21:25
  • Async void is dangerous cause it's non blocking, and you cannot make it blocking, as I know. – Alex Sorokoletov Aug 03 '12 at 21:27
  • @Erik van Brakel, that's pseudocode. Method is actually protected void OnInitialize(), but it's not relevant to question – Alex Sorokoletov Aug 03 '12 at 21:27
  • I see your point, @JonSkeet. AggregateException will do it's job. And yes, it's horrible to code that, but that's only way for this exact situation.Thank you so much for your help! – Alex Sorokoletov Aug 03 '12 at 21:47
  • 4
    You can use `.GetAwaiter().GetResult()` instead of `.AsTask().Wait()` to avoid the `AggregateException`. – Ed Ball Nov 13 '12 at 23:55
-1
    public async void CalculateData()
    {
        await ProcessData();
    }

    private async Task ProcessData()
    {
        await Task.Run(() =>
        {
            //time taking process
        });
    }

Or you can use

public void CalculateData()
{
    ProcessData();
}

private async void ProcessData()
{
    await Task.Run(() =>
    {
        //time taking process
    });
}
Adarsh Babu PR
  • 179
  • 1
  • 5