Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.84/32: Рейтинг темы: голосов - 32, средняя оценка - 4.84
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590

Почему сделано так, что нельзя ожидать async void методы?

22.04.2021, 16:58. Показов 6915. Ответов 18

Студворк — интернет-сервис помощи студентам
Привет!

Чем внутри отличается async void от async Task? Как я понимаю, особо ничем. Для обоих случаев генерируется, если не одинаковый, то очень похожий код. Разница в том, что в случае с void возникшее исключение пробрасывается в поток из пула потоков, а в случае с Task исключение устанавливается внутрь задачи. Или там ещё что-то? Причем и там и там, если в нашем коде есть await, под капотом создается задача, и работает оно в обоих случаях очень похоже, отличается только способ обработки возникшего исключения.

И возникает пара вопросов:
1. Почему не сделали возможность в языке писать await MyVoidMethod()?
2. Пробрасывание исключение в пул потоков, как я понимаю, это следствие невозможности из языка выполнить await. Если это так, то зачем исключение пробрасывать: что бы оно случайно не осталось незамеченным или какие-то есть другие причины этого?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.04.2021, 16:58
Ответы с готовыми решениями:

Почему нельзя несколько раз ожидать ValueTask
Привет! Есть статья про ValueTask, которая является переводом статьи из блога ребят, которые эти самые Task-и делают. В статье...

Почему в async void методе не перехватывается исключение?
Привет! В ряде статей читал о том, что в подобном случае исключение не перехватывается и программа в какой-то момент упадет: ...

Дописать методы void pop_back(void); T& back(void); T& front(void); void erase (iterator p)
Задали задание, и не получается дописать оставшиеся методы: void pop_back(void); T& back(void); T& front(void); void erase...

18
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
22.04.2021, 17:16
Цитата Сообщение от V0fka Посмотреть сообщение
в случае с void возникшее исключение пробрасывается в поток из пула потоков
Зависит от реализации рантайма, языком поведение не регламентируется.

Цитата Сообщение от V0fka Посмотреть сообщение
Почему не сделали возможность в языке писать await MyVoidMethod()?
Потому что await — это оператор, которому нужен операнд.
Что он должен ожидать, если void ничего не возвращает?

Цитата Сообщение от V0fka Посмотреть сообщение
зачем исключение пробрасывать
Это надо спрашивать у разработчиков компилятора/рантайма, но подозреваю что для того, чтобы не давать возможности горе-программистам плодить непонятные баги.
0
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
22.04.2021, 20:10
Цитата Сообщение от V0fka Посмотреть сообщение
в случае с void возникшее исключение пробрасывается в поток из пула потоков
Исключение пробрасывается в SynchronizationContext. Пул потоков это всего лишь один из возможных вариантов (SynchronizationContext по умолчанию).
0
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
23.04.2021, 08:25  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Потому что await — это оператор, которому нужен операнд.
Что он должен ожидать, если void ничего не возвращает?
Я бы мог сказать, что ожидать он должен окончания выполнения метода. Ведь, если я правильно понял, то с технической точки зрения разницы практически нету (по крайней мере в контексте ожидания) между async void и async Task. Или это больше вопрос идеологии, а не технических аспектов?

Цитата Сообщение от kolorotur Посмотреть сообщение
Это надо спрашивать у разработчиков компилятора/рантайма, но подозреваю что для того, чтобы не давать возможности горе-программистам плодить непонятные баги.
А какого рода непонятные баги могут быть? Что-то вроде: где-то там стрельнуло исключение, но т.к. мы не можем сделать над void-ом await или другими словами как-то сказать "стой тут и жди пока метод закончится", то нету возможности узнать о тот как завершился метод (с исключением или без) со всеми вытекающими? Т.е. если бы могли как-то дожидаться завершения метода, то вероятно, такой подход к обработке исключений тут бы не сделали?

Цитата Сообщение от nicolas2008 Посмотреть сообщение
Исключение пробрасывается в SynchronizationContext. Пул потоков это всего лишь один из возможных вариантов (SynchronizationContext по умолчанию).
Спасибо за уточнение!
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
23.04.2021, 12:33
Цитата Сообщение от V0fka Посмотреть сообщение
ожидать он должен окончания выполнения метода.
Так он и ожидает.
Оператор await — это не более, чем разукрашенный return.
В момент вызова await работа метода завершается и управление возвращается в точку вызова.

В C# нет существует асинхронных вызовов. Вызов любого метода всегда синхронный.
В этом легко убедиться:
C#
1
2
3
4
5
6
7
8
// Async!
async void MyVoidMethod()
{
   while (true) ;
}
 
MyVoidMethod();
Console.WriteLine("Кончил");
Вывода в консоль не дождетесь, хотя казалось бы метод async и, естественно, отсутствует await.
Вам даже компилятор услужливо выдаст предупреждение, что метод MyVoidMethod всегда выполняется синхронно.

В языке существует понятие асинхронное ожидаение — это когда выполнение части работы откладывается до тех пор, пока выполняющаяся другая работа не закончится.

Когда компилятор встречает в коде await, он разворачивает это примерно в это:
  1. Получить значение справа от await
  2. Если работа завершилась, то:
    1. Если работа завершилась исключением, то пробросить исключение в текущем контексте
    2. В противном случае продолжать выполнение остального метода
  3. В противном случае вынести продолжение метода в отдельный метод
  4. Подписать делегат на этот метод как продолжение работы
  5. Вернуть новый объект, представляющий выполнение изначальной работы и продолжение метода.

Допустим, реализация вашего MyVoidMethod выглядит так:
C#
1
2
3
4
5
6
7
8
9
// Не void!
async Task MyVoidMethod()
{
    // Что-то делаем
 
   await SomeOtherWork();
 
   // Что-то еще делаем
}
Компилятор ее развернет примерно (очень примерно!) в следующий код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Task MyVoidMethod()
{
   // Что-то делаем
 
   var awaitable = SomeOtherWork();
   var awaiter = awaitable.GetAwaiter();
   if (awaiter.IsCmpleted)
   {
      // Что-то еще делаем
   }
   else
   {
      Action continuation = () =>
      {
           // Что-то еще делаем
      };
      Task originalWorkWithRemainderOfThisMethod = awaitable.ContinueWith(continuation);
      return originalWorkWithRemainderOfThisMethod;
   }
}
В месте вызова MyVoidMethod происходит все то же самое, если MyVoidMethod ожидается через await.

Теперь замените тип возвращаемого значения MyVoidMethod с Task на void. В последней строчке уже ничего нельзя вернуть, т.к. метод void — будет просто завершение работы метода без возврата объекта, представляющего продолжение выполнения остальной части метода — с чем компилятору работать в точке вызова?
1
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
23.04.2021, 14:04  [ТС]
kolorotur, спасибо за развернутый ответ! Но я все равно не понимаю следующего.

Цитата Сообщение от kolorotur Посмотреть сообщение
Компилятор ее развернет примерно (очень примерно!) в следующий код
То что я смотрел, и с Task и с void компилятор разворачивает это все в метод void IAsyncStateMachine.MoveNext(), который в обоих случаях void. И как я понимаю, оно развернется в обоих случаях в код вида:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Task MyVoidMethod()
{
   // Что-то делаем
 
   var awaitable = SomeOtherWork();
   var awaiter = awaitable.GetAwaiter();
   if (awaiter.IsCmpleted)
   {
      // Что-то еще делаем
   }
   else
   {
      Action continuation = () =>
      {
           // Что-то еще делаем
      };
   }
}
Чего я так решил. Я игрался с таким кодом:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static async void ExceptionMethod()
{
    Console.WriteLine("ExceptionMethod, before sleep");
    await Task.Delay(1000);
    Console.WriteLine("ExceptionMethod, after sleep");
 
    throw new ArgumentException();
}
 
static async Task Main(string[] args)
{
    Console.WriteLine("Main, start");
    try
    {
        await Task.Run(ExceptionMethod);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
    Console.WriteLine("Main, finish");
    Console.ReadLine();
}
И посмотрел во что это притворяется (чуть поправил код, поубирал на мой взгляд то, что не имеет отношения к вопросу). Вот в это, как я понимаю, превратился Main

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
void IAsyncStateMachine.MoveNext()
{
    int num = this.<>1__state;
    try
    {
        TaskAwaiter awaiter;
        if (num != 0)
        {
        
            awaiter = Task.Run(new Action(Program.ExceptionMethod)).GetAwaiter();
            if (!awaiter.IsCompleted)
            {
                this.<>1__state = 0;
                this.<>u__1 = awaiter;
                Program.<Main>d__10 <Main>d__ = this;
                this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.<Main>d__10>(ref awaiter, ref <Main>d__);
                return;
            }
        }
        else
        {
            awaiter = this.<>u__1;
            this.<>u__1 = default(TaskAwaiter);
            this.<>1__state = -1;
        }
        awaiter.GetResult();
        Console.WriteLine("Main, finish");
        Console.ReadLine();
    }
    catch (Exception exception)
    {
        this.<>1__state = -2;
        this.<>t__builder.SetException(exception);
        return;
    }
    this.<>1__state = -2;
    this.<>t__builder.SetResult();
}
А в это ExceptionMethod

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
void IAsyncStateMachine.MoveNext()
{
    int num = this.<>1__state;
    try
    {
        TaskAwaiter awaiter;
        if (num != 0)
        {
            Console.WriteLine("ExceptionMethod, before sleep");
            awaiter = Task.Delay(1000).GetAwaiter();
            if (!awaiter.IsCompleted)
            {
                this.<>1__state = 0;
                this.<>u__1 = awaiter;
                Program.<ExceptionMethod>d__9 <ExceptionMethod>d__ = this;
                this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.<ExceptionMethod>d__9>(ref awaiter, ref <ExceptionMethod>d__);
                return;
            }
        }
        else
        {
            awaiter = this.<>u__1;
            this.<>u__1 = default(TaskAwaiter);
            this.<>1__state = -1;
        }
        awaiter.GetResult();
        Console.WriteLine("ExceptionMethod, after sleep");
        throw new ArgumentException();
    }
    catch (Exception exception)
    {
        this.<>1__state = -2;
        this.<>t__builder.SetException(exception);
    }
}
В обоих случаях это void методы.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
23.04.2021, 16:49
Цитата Сообщение от V0fka Посмотреть сообщение
В обоих случаях это void методы.
Суть в том, что в точку вызова возвращаются экземпляры, содержащие это void методы.
Но если асинхронный метод void, то в точку вызова нечего возвращать и не на чем строить машину состояний для проверки полного завершения работы метода.
0
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
24.04.2021, 12:38  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Суть в том, что в точку вызова возвращаются экземпляры, содержащие это void методы.
Сейчас нету под рукой компа с рабочим окружением, но вроде ж в точке вызова ничего и не возвращается. Там, кажется, просто происходит вызов builder.Start(), который вызывает IAsyncStateMachine.MoveNext(). И везде оно void. Или я вас не правильно понимаю?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
24.04.2021, 16:51
Цитата Сообщение от V0fka Посмотреть сообщение
Или я вас не правильно понимаю?
Оно, ага.
Чтобы вызвать MoveNext, должен быть экземпляр, на котором его вызывать.
Этот экземпляр возвращает асинхронный метод в точку вызова.
Если асинхронный метод — void, то он ничего не возвращает и не на чем вызывать MoveNext, следовательно не во что преобразовывать await, как результат — await нельзя использовать с void-методами.

Добавлено через 1 минуту
Это примерно как пытаться использовать foreach на void-возвращающем методе:
C#
1
2
3
void Whatever() { }
 
foreach (var item in Whatever()) // ???
1
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
26.04.2021, 08:45  [ТС]
kolorotur, я теперь, кажется, понял о чем вы выше говорили. Но я теперь не понимаю следующего. AsyncVoidMethodBuilder на самом деле содержит у себя внутри какую-то задачу:

C#
1
2
3
4
5
6
7
8
9
10
11
private Task Task
{
    get
    {
        if (this.m_task == null)
        {
            this.m_task = new Task();
        }
        return this.m_task;
    }
}
Я вижу, что она приватная и вернуть её в точку вызова нельзя. Но на первый взгляд выглядит так, что если бы эта задача была публичной, то вся эта штука могла бы работать так же, как и async Task. Я понимаю, что, скорее всего, это было сделано намеренно, что бы так нельзя было делать. Но интересно почему: по идеологическим причинам или есть какие-то технические причины такого дизайна?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
26.04.2021, 10:28
Цитата Сообщение от V0fka Посмотреть сообщение
AsyncVoidMethodBuilder на самом деле содержит у себя внутри какую-то задачу
Он используется внутри void-метода для построения конечного автомата.
Снаружи этого метода (в точке вызова) строить нечего, т.к. void метод не возвращает никакой информации о проделываемой работе — на то он и void.

Цитата Сообщение от V0fka Посмотреть сообщение
скорее всего, это было сделано намеренно, что бы так нельзя было делать
async void существует с одной-единственной целью: дать возможность писать асинхронные обработчики событий для обратной совместимости с кодом, написанным в до-async времена.
В других ситуациях его использование не имеет смысла.

Цитата Сообщение от V0fka Посмотреть сообщение
по идеологическим причинам или есть какие-то технические причины такого дизайна?
И то, и другое.
Асинхронное ожидание конвертируется в конечный автомат, используя возвращаемое значение асинхронного метода.
Если метод ничего не возвращает, то конечный автомат строить не из чего.
А поскольку async void создан только для обратной совместимости, постольку разработчики не стали тратить впустую время на попытки реализовать какой-то другой механизм ожидания async void методов за ненадобностью: легаси-код нигде не использует await при запуске событий, а новый код может для асинхронных событий использовать делегат, возвращающий Task или любой другой awaitable.
1
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
26.04.2021, 16:07  [ТС]
kolorotur, это не точно, но кажется, начинает потихоньку доходить. Спасибо за ответ!
0
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
27.04.2021, 08:29  [ТС]
kolorotur, с методом void я вроде понял, но все равно интересно, почему бы было не сделать, что бы async void методы превращались компилятором в async Task? Существующий AsyncVoidMethodBuilder это вроде позволяет (в смысле вернуть задачу из него, сделав её публичной). Надо было бы ещё всего лишь поменять тип метода с void на Task. От этого ничего бы не сломалось вроде: для тех, кто вызывал бы метод без ожидания - было бы поведение аналогичное текущему. Но для тех кому надо было бы дождаться - появилась бы такая возможность.
0
 Аватар для Рядовой
1524 / 914 / 329
Регистрация: 17.05.2015
Сообщений: 3,438
27.04.2021, 09:13
Цитата Сообщение от kolorotur Посмотреть сообщение
async void существует с одной-единственной целью: дать возможность писать асинхронные обработчики событий для обратной совместимости с кодом, написанным в до-async времена.
В других ситуациях его использование не имеет смысла.
почему не имеет? Как, например, запустить асинхронный метод из конструктора? Зачем я должен ожидать задачу, которую хочу запустить и забыть?
0
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
27.04.2021, 10:18  [ТС]
Цитата Сообщение от Рядовой Посмотреть сообщение
Как, например, запустить асинхронный метод из конструктора? Зачем я должен ожидать задачу, которую хочу запустить и забыть?
Как обычный метод, без await-а.
2
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
27.04.2021, 10:27
Цитата Сообщение от Рядовой Посмотреть сообщение
Как, например, запустить асинхронный метод из конструктора?
C#
1
2
3
4
public Foo()
{
   DoSomethingAsync();
}
Но сам факт запуска асинхронной или любой другой тяжелой задачи из конструктора — очень мутная идея.
Единственная ответственность конструктора — инициализация памяти, занимаемой объектом.
Что, например, будет твориться, если список таких объектов будет десериализирован?

Цитата Сообщение от Рядовой Посмотреть сообщение
Зачем я должен ожидать задачу, которую хочу запустить и забыть?
Не пишите await — не будет ожидания.

Добавлено через 8 минут
Цитата Сообщение от V0fka Посмотреть сообщение
почему бы было не сделать, что бы async void методы превращались компилятором в async Task?
Наверное потому, что реализация любого функционала не бесплатна и не разработчики должны давать причину по которой что-то не реализовано, а желающие иметь в языке какой-то функционал должны предоставлять убедительные аргументы в пользу траты времени и сил на его реализацию. Ну а поскольку количество создателей языка и бюджет разработки конечны, постольку если кто-то занят реализацией функционала А, то он не занят реализацией функционала Б, потому желающий нового функционала должен не только аргументировать его необходимость, но еще и убедить создателей в том, что этот функционал лучше любого другого, на который можно было бы потратить это время и деньги.
Полагаю, что создатели языка не посчитали "заглушку", созданную исключительно для обратной совместимости, достаточно важным функционалом чтобы тратить на нее больше необходимого минимума.
Но это, конечно, всего лишь мои предположения.
Если интересен ответ именно разработчиков — поинтересуйтесь у них сами.
2
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
29.04.2021, 10:52  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Наверное потому, что реализация любого функционала не бесплатна и не разработчики должны давать причину по которой что-то не реализовано, а желающие иметь в языке какой-то функционал должны предоставлять убедительные аргументы в пользу траты времени и сил на его реализацию. Ну а поскольку количество создателей языка и бюджет разработки конечны, постольку если кто-то занят реализацией функционала А, то он не занят реализацией функционала Б, потому желающий нового функционала должен не только аргументировать его необходимость, но еще и убедить создателей в том, что этот функционал лучше любого другого, на который можно было бы потратить это время и деньги.
Полагаю, что создатели языка не посчитали "заглушку", созданную исключительно для обратной совместимости, достаточно важным функционалом чтобы тратить на нее больше необходимого минимума.
То что вы написали звучит вполне здраво и понятно. Вопросом "почему бы было не сделать" я задаюсь по причине того, что с моей стороны решение выглядит копеечным: просто подменить async void на async Task в коде. Может ещё что-то, но тоже кажется, что это по трудозатратам ерунда.
И мне интересно для себя понять: да, это действительно по трудозатратам ерунда, но решили, что условно даже пол дня тратить на это не целесообразно; либо же на самом деле это совсем не ерунда в техническом плане и все не так просто, как я себе представляю?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
29.04.2021, 11:29
Цитата Сообщение от V0fka Посмотреть сообщение
либо же на самом деле это совсем не ерунда в техническом плане и все не так просто, как я себе представляю?
Конечно не ерунда — вы же меняете возвращаемое значение метода.
Что делать, если этот метод — реализация интерфейса? Или переопределенный метод базового типа?
Как быть с делегатами на этот метод? Внешний же код ничего не знает о том, async этот метод или не async — это деталь реализации метода. Внезапно какой-то void-метод из сторонней сборки нельзя присвоить делегату Action, потому что под капотом он, оказывается, вовсе не void.
Выведение типов в лямбда-выражениях — это будет вообще отдельная песня.

Цитата Сообщение от V0fka Посмотреть сообщение
с моей стороны решение выглядит копеечным
Последний официально изданный спек для пятой версии — 500 страниц текста формата А4.
Сейчас на дворе уже 9-я версия, наверняка можно накинуть еще 100-200 страниц на весь новый функционал.
В таких сложных языках почти не бывает копеечных решений — практически любое изменение устроит цепную реакцию, затрагивающую другие правила языка.
1
86 / 13 / 1
Регистрация: 24.05.2010
Сообщений: 590
29.04.2021, 13:08  [ТС]
kolorotur, теперь стало понятнее. Спасибо за ответ!
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
29.04.2021, 13:08
Помогаю со студенческими работами здесь

Что не так сделано ?
Ребят не могу понять что не так. Программа компилируется и выводит HELLO. А мне нужно что бы : H E L L O В общем нужна не...

Почему в С++ это сделано именно так? Объяснение для НЕ программиста
В этой теме хотелось бы задавать &quot;тупые&quot; вопросы по С++ и получить ответы и объяснения на нормальном человеческом языке, понятном НЕ...

Почему нельзя override private методы?
Собственно тема в заголовке. Я всегда считал, что нельзя так делать ввиду того, что child просто не видит этого метода Parent и собственно...

Что не так сделано с плеером JW Player
Помогите пожалуйста делаю контрольную, небольшой сайт вставил в него видео плеер чтобы можно было видео просмотреть допустим, он вроде...

Калькулятор. Подскажите что сделано не так?
Задание по информатике. Неделю вожусь, не могу понять. Не работает.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Новые блоги и статьи
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru