Тип аргумента 'void' не может быть назначен типу параметра 'System.Action' - PullRequest
16 голосов
/ 02 августа 2010

Это мой тестовый код:

class PassingInActionStatement
{
    static void Main(string[] args)
    {
        var dsufac = new DoSomethingUsefulForAChange();

        dsufac.Do(WriteToConsole);
        dsufac.Do2(s => WriteToConsoleWithSomethingExtra("Test"));
        dsufac.Do(WriteToConsoleWithSomethingExtra("Test")); // Does not compile
    }

    internal static void WriteToConsole()
    {
        Console.WriteLine("Done");
    }

    internal static void WriteToConsoleWithSomethingExtra(String input)
    {
        Console.WriteLine(input);
    }
}

internal class DoSomethingUsefulForAChange
{
    internal void Do(Action action)
    {
        action();
    }

    internal void Do2(Action<String> action)
    {
        action("");
    }
}

Первые 2 звонка работают, но мне интересно, почему третий не работает.Мне не нравится код внутри Do2, потому что мне кажется странным, что у меня там есть тип action(""), чтобы заставить его работать.

Может кто-нибудь объяснить, пожалуйста, две вещи, которые я не понимаю, пожалуйста?

  1. Почему я не могу написать третью строку с вызовом Do
  2. Почему я должен написать действие (""), чтобы заставить его работать в Do2

Ответы [ 4 ]

34 голосов
/ 02 августа 2010
dsufac.Do(WriteToConsoleWithSomethingExtra("Test"));

фактически сначала вызывает функцию (WriteToConsoleWithSomethingExtra("Test")), а затем пытается передать результат в Do.Поскольку нет результата (void), это невозможно.

То, что вы на самом деле хотите, это:

dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test"));

Внутренняя часть объявляет функциюничего не берет (бит () =>), который вызывает WriteToConsoleWithSomethingExtra("Test") при выполнении. Тогда ваш dsufac.Do вызов получит действие, как и ожидалось.

Что касается Do2 - вы объявили, что принимаете Action<String>, что означает, что actionэто функция, которая принимает один аргумент .Вы должны передать ему строку.Эта строка может быть пустой, как в вашем примере action(""), или она может передаваться извне, как в следующем примере:

dsufac.Do3(WriteToConsole, "Test");

...

internal void Do3(Action<String> action, String str)
{
    action(str);
}
3 голосов
/ 02 августа 2010

в вашем коде

dsufac.Do(WriteToConsoleWithSomethingExtra("Test"));

интерпретируется как следующее

var variable = WriteToConsoleWithSomethingExtra("Test");
dsufac.Do(variable);

Поскольку возвращаемый тип WriteToConsoleWithSomethingExtra ("Test") не имеет значения, вы не можете передать его в dsufac.Do (). Вот почему его не скомпилировать. Но для первого

dsufac.Do(WriteToConsole);

вы не вызываете функцию, скорее вы передаете ее как группу методов, которая позже вызывается в методе Do () объекта dsufac. Но если вы хотите написать третью строку как первую, вы можете использовать

dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test"));
1 голос
/ 25 августа 2010

Некоторое время я делал что-то подобное в приложении Silverlight.Теперь, когда он запускается, часть его ломается.
Это происходит в дочернем окне Silverlight:

(my object context).SaveChanges(() => ChangesSaved());

private void ChagngesSaved()
{
   DialogResult = true: // is supposed to close the child window. line gets hit, does not close
}
1 голос
/ 02 августа 2010
  1. Do ожидает Action (т. Е. Метод, который не принимает параметров и не возвращает значений).Следовательно, WriteToConsoleWithSomethingExtra не является допустимым соответствием - принимает один строковый параметр.
  2. Do2 принимает Action<T> (то есть метод, который принимает один параметр T и не возвращает значения).Следовательно, когда вы вызываете делегат / действие, вам нужно указать один параметр типа T, здесь String.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...