Reputation: 207
I have a method which fetches some values from Firebase as below:
void getTable(Action<IDictionary> callBack)
{
// function & data initialized here
function.CallAsync(data).ContinueWith((callTask) =>
{
if (callTask.IsFaulted)
callBack(null);
else if (callTask.IsCompleted)
{
Debug.Log("I am being executed when done");
var result = (IDictionary) callTask.Result.Data;
callBack(result);
}
});
}
I call this method from another method as like:
public void GetTable(ref string valueReturned)
{
string val = null;
getTable((dictionary =>
{
Debug.Log("Done getting values");
val = (string) dictionary["someValue"]; // returns "testValue" to val
}));
valueReturned = val;
Debug.Log("Value is:" + valueReturned);
Debug.Log("Completed Execution");
}
Expected Output:
What output I am getting is:
I tried to assign "valueReturned" within the lambda expression of GetTable method. But it gave error : "Cannot user ref parametre inside a lambda expression"
Upvotes: 0
Views: 1931
Reputation: 8363
If we strip down your private method to the core it's nothing more than this:
private async Task<IDictionary> getTable()
{
// function & data initialized here
var result = await function.CallAsync(data);
return result?.Data;
}
public async Task<string> GetTable()
{
var dictionary = await getTable();
var valueReturned = (string)dictionary["someValue"]; // returns "testValue" to val
Debug.Log("Value is:" + valueReturned);
Debug.Log("Completed Execution");
return valueReturned;
}
Only asyn can't have ref in parametrs. You must either return Task or make call sync:
public void GetTable(ref string valueReturned)
{
var dictionary = getTable().Result;
valueReturned = (string)dictionary["someValue"]; // returns "testValue" to val
Debug.Log("Value is:" + valueReturned);
Debug.Log("Completed Execution");
}
As @Miral said: "that design is wrong". From the asyn/await point of view we could refactor both functions to one simply async methode:
public async Task<string> GetTableAsync()
{
// <function & data initialized here>
var result = await function.CallAsync(data);
var dictionary = result?.Data;
return dictionary == null ? null: (string)dictionary["someValue"];
}
Upvotes: 1
Reputation: 143233
Consider returning Task
from getTable
and await
ing it in GetTable
:
Task getTable(Action<IDictionary> callBack)
{
// function & data initialized here
return function.CallAsync(data).ContinueWith((callTask) =>
{
if (callTask.IsFaulted)
callBack(null);
else if (callTask.IsCompleted)
{
Debug.Log("I am being executed when done");
var result = (IDictionary) callTask.Result.Data;
callBack(result);
}
});
}
public Task<string> GetTable()
{
string val = await getTable((dictionary =>
{
Debug.Log("Done getting values");
val = (string) dictionary["someValue"]; // returns "testValue" to val
}));
Debug.Log("Value is:" + val);
Debug.Log("Completed Execution");
return val;
}
Otherwise your getTable
method starts a Task
and continues execution, so GetTable
assigns null
to valueReturned
(assuming that CallAsync
runs long enough) and proceeds. Also I would say that you can just return Task<IDictionary>
from getTable
.
If for some reason you can't make your code asynchronous there are multiple options to run async method synchronously, dependent on your context some can be more appropriate than others, but either way you should approach this with caution.
Upvotes: 1
Reputation: 13095
A more idiomatic way to write getTable
would be:
async Task getTable(Action<IDictionary> callBack)
{
IDictionary result;
try
{
result = await function.CallAsync(data);
}
catch
{
result = null;
}
callback(result);
}
(Whether this is actually a good idea is a different question, since you're sacrificing error information and converting an async method into a callback is usually a bit pointless...)
But your GetTable
method is simply doomed to failure. You can never return the result of an async call in an output parameter, because the outer function has already exited before the inner call completes. The only way this could possibly work is if GetTable
does a blocking wait on getTable
, which then destroys the whole point of using async in the first place.
The only real answer is that your current design is wrong, and you need to do this differently. Async all the way up is the only way to go.
Upvotes: 1