Please, observe the following trivial .NET 4.5 code:
var tcs = new TaskCompletionSource<object>("Hello");
var t1 = tcs.Task;
var t2 = t1.ContinueWith((t, state) => 0, "Hello");
var t3 = t2.ContinueWith((t, state) => new Task<int>(_ => 0, state), "Hello");
var t4 = t3.Unwrap();
Trace.Assert("Hello".Equals(t1.AsyncState), "t1.AsyncState is broken!");
Trace.Assert("Hello".Equals(t2.AsyncState), "t2.AsyncState is broken!");
Trace.Assert("Hello".Equals(t3.AsyncState), "t3.AsyncState is broken!");
Trace.Assert("Hello".Equals(t4.AsyncState), "t4.AsyncState is broken!");
The last assertion fails, which breaks my code (slightly less contrived than this sample).
My question is how to make the task state survive unwrapping? Is there a way to manually unwrap with the state preservation?
Right now, I do not see any other option, except avoiding the default Unwrap() method. Instead, I found the following workaround to be adequate:
var t4 = t3.ContinueWith((t, _) => t.Result.Result, t3.AsyncState);
I will package it as my own extension method, something like FixedUnwrap():
public static Task<TResult> FixedUnwrap<TResult>(this Task<Task<TResult>> task)
{
return task.ContinueWith((t, _) => t.Result.Result, task.AsyncState);
}
IMPORTANT UPDATE
The proposed implementation is wrong! The unwrapped task must continue when the nested task is done, whereas the given version continues when the wrapper task is done. It is very wrong.
Please, find below the correct one (two versions):
public static Task TaskUnwrap(this Task<Task> task)
{
return task.Unwrap().ContinueWith((t, _) =>
{
if (t.Exception != null)
{
throw t.Exception;
}
}, task.AsyncState);
}
public static Task<TResult> TaskUnwrap<TResult>(this Task<Task<TResult>> task)
{
return task.Unwrap().ContinueWith((t, _) => t.Result, task.AsyncState);
}
Related
I am trying to create a method to convert a List to Future<List>.
This is the method I created.
static Future<List<Product?>> fromProductRefList(
List<DocumentReference> ref) async {
List<Product> shopProductList = [];
ref.forEach((productRef) async {
final productDoc = productRef.get();
final product = await Product.fromDocument(await productDoc);
shopProductList.add(product!);
});
print('shopProductList: $shopProductList');
return shopProductList;
}
and called it in cubit,
void mapProductToState() async {
emit(state.copyWith(status: MyProductStatus.loadding));
final shop = _shopBloc.state.shop;
List<Product?> productList = [];
if (shop.shopProductRef.isNotEmpty) {
final productList = Product.fromProductRefList(shop.shopProductRef);
}
emit(state.copyWith(
shop: shop,
productList: productList,
status: MyProductStatus.loaded,
));
}
VScode shows no error but when I run the code, fromProductRefList return empty list. Seems like fromProductRefList did not wait for the Document actually get() from the database and just return.
When I add a second delay in fromProductRefList before returning the shopProductList, everything works as expected.
I have read another question on stackoverflow suggest using asyncMap() but I am not sure how to apply it in my case.
Edit:
When I add a delay, the method return without any issue. If not, it will return a empty list
static Future<List<Product?>> fromProductRefList(
List<DocumentReference> ref) async {
List<Product> shopProductList = [];
ref.forEach((productRef) async {
final productDoc = productRef.get();
final product = await Product.fromDocument(await productDoc);
shopProductList.add(product!);
});
await Future.delayed(const Duration(milliseconds: 500));
print('shopProductList: $shopProductList');
return shopProductList;
}
Thank you.
You are missing the await keyword, to actually wait for the call. It only compiles, because you also declare a new variable of name productList, shadowing the already existing one.
So this line:
final productList = Product.fromProductRefList(shop.shopProductRef);
should read:
productList = await Product.fromProductRefList(shop.shopProductRef);
In addition, this does not do what you think it does:
ref.forEach((productRef) async {
It does not wait for each call. Please use a normal for flow control structure and await the async call, not the forEach method. The forEach method will no wait for the Futures returned from the methods.
Greeting,
I'm currently facing a problem that my coroutine can't start. This is the first time I facing this issues and I can't find a proper solution online. Much appreciated if anyone can point me to the right direction to solve this issue.
Here are the code.
path_reference.GetDownloadUrlAsync().ContinueWith((Task<Uri> task) => {
if (!task.IsFaulted && !task.IsCanceled)
{
Debug.Log("Download URL: " + task.Result);
StartCoroutine(DownloadStuff(task.Result));
}
else
{
Debug.Log(task.Exception.ToString());
}
});
}
IEnumerator DownloadStuff(Uri uri)
{
Debug.Log("Start Download");
using (var www = UnityWebRequestTexture.GetTexture(uri))
{
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
var texture = DownloadHandlerTexture.GetContent(www);
//Texture2D texture = new Texture2D(1, 1);
//if you need sprite for SpriteRenderer or Image
Sprite sprite = Sprite.Create(texture, new Rect(0.0f, 0.0f, texture.width,
texture.height), new Vector2(0.5f, 0.5f), 100.0f);
Debug.Log("Finished downloading!");
}
Debug.Log(www.downloadProgress);
}
}'
The task returned by Firebase probably finishes execution on a thread other than the main thread, and Unity coroutines can only run on the main thread.
Unity's support of multithreading and async is pretty spotty, including "eating" some errors if the continuations of those errors would execute on another thread other than the main thread.
To fix this, you need to change the function that starts your coroutine:
try {
// Important: ConfigureAwait(true) ensures the code after this will run in the
// same thread as the code before (which is the main thread!)
var url = await path_reference.GetDownloadUrlAsync().ConfigureAwait(true);
StartCoroutine(DownloadStuff(url));
} catch (Exception ex) {
// Tip: when logging errors, use LogException and pass the whole exception,
// that way you will get pretty links to the error line in the whole stack trace.
Debug.LogException(ex);
}
As an aside, I usually have a few extension methods on all my projects to deal with that while staying in async-world instead of coroutine-world (because at least with async I can catch errors and not just "halt and catch fire" like Unity's coroutines)
The main ones are:
public static Task ToTask(this YieldInstruction self, MonoBehaviour owner) {
var source = new TaskCompletionSource<object>();
IEnumerable Routine() {
yield return self;
source.SetResult(null);
}
return source.Task;
}
private static Task SendAsync(this UnityWebRequest self, MonoBehaviour owner) {
var source = new TaskCompletionSource<object>();
await self.SendWebRequest().ToTask(owner);
if (
self.isHttpError
|| self.isNetworkError
) {
source.SetException(new Exception(request.error));
yield break;
}
source.SetResult(null);
}
Which you can use like this, inside a MonoBehaviour:
await new WaitForSeconds(0.2f).ToTask(this);
UnityWebRequest request = /* etc */;
await request.SendAsync(this);
var texture = DownloadHandlerTexture.GetContent(request);
Note that these methods do not require ConfigureAwait, since their SetResult/SetException invocations are ran from Unity-provided coroutine continuations.
I am trying the async examples from the GNOME project site. I get the follwoing warning which I don't under stand on how to fix.
async.vala:8.2-8.17: warning: delegates with scope="async" must be owned
Code
async double do_calc_in_bg(double val) throws ThreadError {
SourceFunc callback = do_calc_in_bg.callback;
double[] output = new double[1];
// Hold reference to closure to keep it from being freed whilst
// thread is active.
// WARNING HERE
ThreadFunc<bool> run = () => {
// Perform a dummy slow calculation.
// (Insert real-life time-consuming algorithm here.)
double result = 0;
for (int a = 0; a<100000000; a++)
result += val * a;
output[0] = result;
Idle.add((owned) callback);
return true;
};
new Thread<bool>("thread-example", run);
yield;
return output[0];
}
void main(string[] args) {
var loop = new MainLoop();
do_calc_in_bg.begin(0.001, (obj, res) => {
try {
double result = do_calc_in_bg.end(res);
stderr.printf(#"Result: $result\n");
} catch (ThreadError e) {
string msg = e.message;
stderr.printf(#"Thread error: $msg\n");
}
loop.quit();
});
loop.run();
}
The warning is pointing at the run variable inside the async function. Who or what needs to be owned? The reference to the closure?
The delegate needs to have a well defined owner all the time. The error message is a bit misleading.
To fix it you have to explicitly transfer the ownership from the delegate to the thread constructor:
new Thread<bool>("thread-example", (owned) run);
Instead of
new Thread<bool>("thread-example", run);
See also: https://wiki.gnome.org/Projects/Vala/Tutorial#Ownership
PS: The generated C code is fine in both cases. (at least with valac 0.46.6)
I'm trying to verify a method call using Moq, but I can't quite get the syntax right. Currently, I've got this as my verify:
repository.Verify(x => x.ExecuteNonQuery("fav_AddFavorites", new
{
fid = 123,
inputStr = "000456"
}), Times.Once());
The code compiles, but the test fails with the error:
Expected invocation on the mock once, but was 0 times:
x => x.ExecuteNonQuery("fav_AddFavorites", new <>f__AnonymousType0<Int32, String>(123, "000456"))
No setups configured.
Performed invocations:
IRepository.ExecuteNonQuery("fav_AddFavorites", { fid = 123, inputStr = 000456 })
How can I verify the method call and match the method parameters for an anonymous type?
UPDATE
To answer the questions:
I am trying to verify both that the method was called and that the parameters are correct.
The signature of the method I'm trying to verify is:
int ExecuteNonQuery(string query, object param = null);
The setup code is simply:
repository = new Mock<IRepository>();
UPDATE 2
It looks like this is a problem with Moq and how it handles anonymous types in .Net. The code posted by Paul Matovich runs fine, however, once the code and the test are in different assemblies the test fails.
This Passes
public class Class1
{
private Class2 _Class2;
public Class1(Class2 class2)
{
_Class2 = class2;
}
public void DoSomething(string s)
{
_Class2.ExecuteNonQuery(s, new { fid = 123, inputStr = "000456" });
}
}
public class Class2
{
public virtual void ExecuteNonQuery(string s, object o)
{
}
}
/// <summary>
///A test for ExecuteNonQuery
///</summary>
[TestMethod()]
public void ExecuteNonQueryTest()
{
string testString = "Hello";
var Class2Stub = new Mock<Class2>();
Class1 target = new Class1(Class2Stub.Object);
target.DoSomething(testString);
Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.Equals(new { fid = 123, inputStr = "000456" }))), Times.Once());
}
##Update##
That is strange, it doesn't work in different assemblies. Someone can give us the long definition about why the object.equals from different assemblies behaves differently, but for different assemblies, this will work, any variance in the object values will return a different hash code.
Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.GetHashCode() == (new { fid = 123, inputStr = "000456" }).GetHashCode())), Times.Once());
One option is to "verify" it in a Callback. Obviously this needs to be done at Setup time, e.g.:
aMock.Setup(x => x.Method(It.IsAny<object>())).Callback<object>(
(p1) =>
{
dynamic o = p1;
Assert.That(o.Name, Is.EqualTo("Bilbo"));
});
None of the answers are great when your test assembly is different than the system under test's assembly (really common). Here's my solution that uses JSON serialization and then strings comparison.
Test Helper Function:
using Newtonsoft.Json;
public static class VerifyHelper
{
public static bool AreEqualObjects(object expected, object actual)
{
var expectedJson = JsonConvert.SerializeObject(expected);
var actualJson = JsonConvert.SerializeObject(actual);
return expectedJson == actualJson;
}
}
Example System Under Test:
public void DoWork(string input)
{
var obj = new { Prop1 = input };
dependency.SomeDependencyFunction(obj);
}
Example Unit Test:
var expectedObject = new { Prop1 = "foo" };
sut.DoWork("foo");
dependency.Verify(x => x.SomeDependencyFunction(It.Is<object>(y => VerifyHelper.AreEqualObjects(expectedObject, y))), Times.Once());
This solution is really simple, and I think makes the unit test easier to understand as opposed to the other answers in this thread. However, because it using simple string comparison, the test's anonymous object has to be set up exactly the same as the system under the test's anonymous object. Ergo, let's say you only cared to verify the value of a single property, but your system under test sets additional properties on the anonymous object, your unit test will need to set all those other properties (and in the same exact order) for the helper function to return true.
I created a reusable method based on Pauls answer:
object ItIsAnonymousObject(object value)
{
return It.Is<object>(o => o.GetHashCode() == value.GetHashCode());
}
...
dependency.Verify(
x => x.SomeDependencyFunction(ItIsAnonymousObject(new { Prop1 = "foo" })),
Times.Once());
Also, this can be used for property name case-insensitive comparison:
protected object ItIsAnonymousObject(object value)
{
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
return It.Is<object>(o => JsonSerializer.Serialize(o, options) == JsonSerializer.Serialize(value, options));
}
I'm new to RX, and I have my desired scenario working well, but it seems to me there must be a simpler or more elegant way to achieve this. What I have is an IObservable<T> and I want to subscribe to it in such a way that I end up with an IObservable<U>, by triggering an asynchronous operation that generates a U for each T it sees.
What I have so far (that works great, but seems cumbersome) uses an intermediate event stream and goes something like this:
public class Converter {
public event EventHandler<UArgs> UDone;
public IConnectableObservable<U> ToUs(IObservable<T> ts) {
var us = Observable.FromEvent<UArgs>(this, "UDone").Select(e => e.EventArgs.U).Replay();
ts.Subscribe(t => Observable.Start(() => OnUDone(new U(t))));
return us;
}
private void OnUDone(U u) {
var uDone = UDone;
if (uDone != null) {
uDone(this, u);
}
}
}
...
var c = new Converter();
IConnectableObservable<T> ts = ...;
var us = c.ToUs(ts);
us.Connect();
...
I'm sure I'm missing a much simpler way to do this...
SelectMany should do what you need, to flatten out the IO<IO<T>>
Observable.Range(1, 10)
.Select(ii => Observable.Start(() =>
string.Format("{0} {1}", ii, Thread.CurrentThread.ManagedThreadId)))
.SelectMany(id=>id)
.Subscribe(Console.WriteLine);
This is exactly what SelectMany is for:
IObservable<int> ts
IObservable<string> us = ts.SelectMany(t => StartAsync(t));
us.Subscribe(u =>
Console.WriteLine("StartAsync completed with {0}", u));
...
private IObservable<string> StartAsync(int t)
{
return Observable.Return(t.ToString())
.Delay(TimeSpan.FromSeconds(1));
}
Keep in mind that if StartAsync has a variable completion time, you may receive the output values in a different order from the input values.