Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Передача объекта по ссылке в асинхронный метод / 10 сообщений из 10, страница 1 из 1
18.06.2018, 10:24
    #39661844
vb_sub
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
Всем привет, компилятор при попытке передачи объекта класса в асинхронный метод по ссылке пишет ошибку:
У асинхронных методов не может быть параметров ref и out
, однако если предварительно упаковать этот объект в результат Linq-запроса, то его осуществить можно.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
public class Item
    {

        /// <summary>
        /// Смотрим по этому свойству изменился ли объект
        /// </summary>
        public bool  Changed { get; set; }

        /// <summary>
        /// Идентификатор для использования в linq-запросе
        /// </summary>
        public int id { get; set; }

        public Item( int _id)
        {
            id = _id;

        }
    }



class Program
    {
        static  void Main(string[] args)
        {
            List<Item> lst = new List<Item>();

            Item item1 = new Item(1);
            Item item2 = new Item(2);

            lst.Add(item1);
            lst.Add(item2);
            
            // Запихиваем асинхронный метод  в Task, чтобы можно было вставить await в main,
            // хотя мелкософты обезащали сделать async Main в Visual Studio 2017-чет не работает "из коробки"- по ходу для 
            // консольных приложений Main так и остался синхронным

            var t = Task.Run(
                   async () =>
                    {
                        // отбираем только элементы item1 
                        var p1 = lst.Where(r => r.id == 1).FirstOrDefault();
                        //значение передается по ссылку и в то же время метод асинхронный
                        await change_propertyByLinq(p1);
                        System.Diagnostics.Debug.Write("0 " + item1.Changed + "\n");
                     }
                    );

            System.Diagnostics.Debug.Write("1 " +  item1.Changed +"\n");
            Task.WaitAll(t);
            System.Diagnostics.Debug.Write("2 " + item1.Changed + "\n");

            // 0 True
            // 1 False
            // 2 True
        }



        /// <summary>
        /// Метод принимает аргумент как по "ссылке", потому что в "Main" при проверки 
        /// свойства "Changed" видим, что оно поменялось
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private static  async Task change_propertyByLinq(Item item)
        {      
                item.Changed = true;
        }


        ///Этот метод уже работать не будет, хотя он делает то же самое что и вышестоящий-изменяет свойство объекта по ссылке
        /// У асинхронных методов не может быть параметров ref и out
        //private static async Task change_ItemByRef(ref Item item)
        //{
       // item.Changed = true;
        //}
    }



По умолчанию C# передает аргументы в методы по значению, однако метод change_propertyByLinq отрабатывает как будто ему передали аргумент по ссылке. Вопрос:
это частный случай и не факт что если в других ситуациях я передам также объект как результат linq, то оно передасться по ссылке?
Почему такое противоречие, что асинхронный метод не может принимать аргументы по ссылке, но если немного подизменить код то получается аналогичный результат?
...
Рейтинг: 0 / 0
18.06.2018, 10:54
    #39661862
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
авторПо умолчанию C# передает аргументы в методы по значению
это относится только в структурам, класс передаются по ссылке
...
Рейтинг: 0 / 0
18.06.2018, 11:12
    #39661876
vb_sub
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
Roman Mejtes,
тогда бы
Код: c#
1.
 private static  async Task change_propertyByLinq(Item item)


и
Код: c#
1.
private static async Task change_ItemByRef(ref Item item)


было бы идентичным
...
Рейтинг: 0 / 0
18.06.2018, 11:30
    #39661887
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
vb_subRoman Mejtes,
тогда бы
Код: c#
1.
 private static  async Task change_propertyByLinq(Item item)


и
Код: c#
1.
private static async Task change_ItemByRef(ref Item item)


было бы идентичным
Ничего подобного. Ссылка на локальную переменную - это адрес в куче, хранящийся на стеке, и этот адрес как ссылка передается по значению, поэтому непосредственно саму ссылку, переданную в метод, модифицировать нельзя. Если ссылка передается ref-параметром, то передается не сама ссылка, а её адрес на стеке, и саму ссылку уже можно модифицировать:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
class Program
{
  static void Main()
  {
    var sb = new StringBuilder();
    sb.Append("Foo");
    Foo1(sb);
    Console.WriteLine(sb);
    Foo2(ref sb);
    Console.WriteLine(sb);
  }

  static void Foo1(StringBuilder sb)
  {
    sb = new StringBuilder();
    sb.Append("Foo1");
  }
  static void Foo2(ref StringBuilder sb)
  {
    sb = new StringBuilder();
    sb.Append("Foo2");
  }
}


в консоли:

Код: plaintext
1.
Foo
Foo2

- т.е. в первом случае попытка модфикации ссылки ничем не закончилась - как только мы вышли из Foo1, его фрейм стека зачистился, и в точке возврата мы опять имели дело со старой ссылкой на StringBuilder. Во втором случае мы вполне успешно модифицировали ссылку, т.к. был передан её адрес на стеке метода Main, и далее уже имели дело с модифицированной ссылкой.
...
Рейтинг: 0 / 0
18.06.2018, 11:31
    #39661888
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
P.S. Я думаю, разница между модификацией состояния объекта по ссылке, и модификация самой ссылки, вопросов не вызывает?
...
Рейтинг: 0 / 0
18.06.2018, 12:09
    #39661915
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
vb_subУ асинхронных методов не может быть параметров ref и out
, однако если предварительно упаковать этот объект в результат Linq-запроса, то его осуществить можно.

Нет, не можно. Это будет совсем другое.
...
Рейтинг: 0 / 0
22.06.2018, 10:06
    #39663965
monstrU
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
Сон Веры Павловны,
Код: c#
1.
2.
3.
4.
5.
вот если расширить твой пример - добавим класс
 public class Person
    {
        public string Name { get; set; } 
    }



и дальше

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
static void Main(string[] args)
        {
            var sb = new StringBuilder();
            sb.Append("Foo");
            Foo1(sb);
            Console.WriteLine(sb);
            Foo2(ref sb);
            Console.WriteLine(sb);
            var person= new Person();
            person.Name = "ver1";
            ChangePerson(person);
            Console.WriteLine(person.Name);
            Console.ReadLine();
        }

static void ChangePerson(Person obj)
        {
            obj.Name = "ver2";
        }



после завершения получим
Foo
Foo2
ver2

- в чем то различия у классов StringBuilder и Person ?
ведь ссылка объект класса Person передан в метод ChangePerson, изменялась ссылка и по завершении метода изменения сохраняются.

у StringBuilder изменения ссылки не сохраняются после выхода из метода, у Person - сохраняются - получается так ?
...
Рейтинг: 0 / 0
22.06.2018, 11:03
    #39664032
LR
LR
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
monstrUу StringBuilder изменения ссылки не сохраняются после выхода из метода, у Person - сохраняются - получается так ?Нет. Почитайте документацию https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters Parameters declared for a method without in, ref or out, are passed to the called method by value. That value can be changed in the method, but the changed value will not be retained when control passes back to the calling procedure. By using a method parameter keyword, you can change this behavior.
А "расширить" пример С.В.П. следовало бы как-то так
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
static void Main(string[] args)
{
    var person = new Person();
    person.Name = "ver1";
    ChangePerson(person);
    Console.WriteLine(person.Name);
    ChangePerson(ref person);
    Console.WriteLine(person.Name);
    ChangePersonOut(out person);
    Console.WriteLine(person.Name);
    Console.ReadLine();
}
static void ChangePerson(Person obj) => obj = new Person() { Name = "ver2" };
static void ChangePerson(ref Person obj) => obj = new Person() { Name = "ver2" };
static void ChangePersonOut(out Person obj) => obj = new Person() { Name = "verOut" };
...
Рейтинг: 0 / 0
22.06.2018, 11:28
    #39664064
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
monstrU- в чем то различия у классов StringBuilder и Person ?
ведь ссылка объект класса Person передан в метод ChangePerson, изменялась ссылка и по завершении метода изменения сохраняются.

у StringBuilder изменения ссылки не сохраняются после выхода из метода, у Person - сохраняются - получается так ?
И с чего же вдруг у Person в вышеприведенном изменилась ссылка? Изменилось содержимое объекта в куче по адресу, куда указывает ссылка, а сама ссылка осталось той же.
...
Рейтинг: 0 / 0
22.06.2018, 11:41
    #39664079
monstrU
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Передача объекта по ссылке в асинхронный метод
Сон Веры ПавловныmonstrU- в чем то различия у классов StringBuilder и Person ?
ведь ссылка объект класса Person передан в метод ChangePerson, изменялась ссылка и по завершении метода изменения сохраняются.

у StringBuilder изменения ссылки не сохраняются после выхода из метода, у Person - сохраняются - получается так ?
И с чего же вдруг у Person в вышеприведенном изменилась ссылка? Изменилось содержимое объекта в куче по адресу, куда указывает ссылка, а сама ссылка осталось той же.

спасибо
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Передача объекта по ссылке в асинхронный метод / 10 сообщений из 10, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]