Ref in async Task

2019-05-07 08:22发布

How I can to pass a reference as a parameter to Async method in Windows Store App ?
I'm looking for something like this:

var a = DoThis(ref obj.value);

public async Task DoThis(ref int value)
{
    value = 10;
}

But error:

Async methods cannot have ref or out parameters

Has any another way?

Note:
I need to pass exactly obj.value. This method would be used by different types of objects, by same type of objects, by one object, but I will pass obj.val_1, obj.val_2 or obj.val_10. All values will be same type (for ex string)

4条回答
干净又极端
2楼-- · 2019-05-07 08:31

You can't do this as you have it (as you know). So, a few work arounds:

You can do this by passing the initial object since it will be a reference type

var a = DoThis(obj);  

public async Task DoThis(object obj) //replace the object with the actual object type
{
    obj.value = 10;
}

EDIT

Based upon your comments, create an interface and have your classes implement it (providing it's always the same type you want to pass). Then you can pass the interface which is shared (maybe over kill, depends on your needs, or even unrealistic amount of work).

Or, provide a base class with the property! (I don't like this suggestion but since you're asking for something which can't be done it may suffice although I don't recommend it).

An example of the interface is here (not using what you have, but close enough using a Colsone App)

using System;

namespace InterfacesReferenceTypes
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass mc = new MyClass();
            DoThis(mc);
            Console.WriteLine(mc.Number);
            Console.ReadKey();
        }

        static void DoThis(IDemo id)
        {
            id.Number = 10;
        }
     }

    class MyClass : IDemo
    {
        //other props and methods etc
        public int Number { get; set; }
    }

    interface IDemo
    {
        int Number { get; set; }
    }
}

EDIT2

After next comments, you will have to still use an interface, but re assign the value afterwards. I'm sure there is a better way to do this, but this works:

using System.Text;

namespace InterfacesRerefenceTypes
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass mc = new MyClass();
            Console.WriteLine(mc.Number);
            mc.val1 = 3;
            mc.val2 = 5;
            mc.Number = mc.val2;
            DoThis(mc);
            mc.val2 = mc.Number;

            Console.WriteLine(mc.val2);
            Console.ReadKey();
        }

        static void DoThis(IDemo id)
        {
            id.Number = 15;
        }
    }

    class MyClass : IDemo
    {
        public int val1 { get; set; }
        public int val2 { get; set; }
        public int Number { get; set; }
    }

    interface IDemo
    {
        int Number { get; set; }
    }
}
查看更多
一纸荒年 Trace。
3楼-- · 2019-05-07 08:53

If you don't care about a little overhead and possibly prolonged lifetime of your objects, you could emulate the ref behavior by passing a setter and a getter method to the function, like this:

public async Task DoStuff(Func<int> getter, Action<int> setter)
{
    var value1 = getter();
    await DoSomeOtherAsyncStuff();
    setter(value1 * value1);
}

And call it like this:

await DoStuff(() => obj.Value, x => obj.Value = x);
查看更多
Animai°情兽
4楼-- · 2019-05-07 08:54

You could directly pass the object itself and set the value of the corresponding property inside the method:

var a = DoThis(obj);

public async Task DoThis(SomeObject o)
{
    o.value = 10;
}

And if you do not have such object simply write one and have the async method take that object as parameter:

public class SomeObject
{
    public int Value { get; set; }
}
查看更多
别忘想泡老子
5楼-- · 2019-05-07 08:55

You can always use the Task<> class and return the desired value. Then Your code would look something like:

var a = DoThis(obj.value);
obj.value = a.Result;

public async Task<int> DoThis(int value)
{
    int result = value + 10; //compute the resulting value
    return result;
}

EDIT

Ok, the other way to go with this that I can think of is encapsulating the update of the given object's member in a method and then passing an action invoking this method as the task's argument, like so:

var a = DoThis(() => ChangeValue(ref obj.value));

public void ChangeValue(ref int val)
{
    val = 10;
}

public async Task DoThis(Action act)
{
    var t = new Task(act);
    t.Start();
    await t;
}

As far as I tested it the change was made in the child thread, but still it's effect was visible in the parent thread. Hope this helps You.

查看更多
登录 后发表回答