powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Передача объекта по ссылке в асинхронный метод
10 сообщений из 10, страница 1 из 1
Передача объекта по ссылке в асинхронный метод
    #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
Передача объекта по ссылке в асинхронный метод
    #39661862
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторПо умолчанию C# передает аргументы в методы по значению
это относится только в структурам, класс передаются по ссылке
...
Рейтинг: 0 / 0
Передача объекта по ссылке в асинхронный метод
    #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
Передача объекта по ссылке в асинхронный метод
    #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
Передача объекта по ссылке в асинхронный метод
    #39661888
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
P.S. Я думаю, разница между модификацией состояния объекта по ссылке, и модификация самой ссылки, вопросов не вызывает?
...
Рейтинг: 0 / 0
Передача объекта по ссылке в асинхронный метод
    #39661915
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_subУ асинхронных методов не может быть параметров ref и out
, однако если предварительно упаковать этот объект в результат Linq-запроса, то его осуществить можно.

Нет, не можно. Это будет совсем другое.
...
Рейтинг: 0 / 0
Передача объекта по ссылке в асинхронный метод
    #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
Передача объекта по ссылке в асинхронный метод
    #39664032
Фотография 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
Передача объекта по ссылке в асинхронный метод
    #39664064
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
monstrU- в чем то различия у классов StringBuilder и Person ?
ведь ссылка объект класса Person передан в метод ChangePerson, изменялась ссылка и по завершении метода изменения сохраняются.

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

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

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


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