+1 за редкое сочетание того, что вы новичок в программировании и задаете хороший вопрос: вы понимаете, что хотите сделать, и хорошо это объясняете, вы просто не знаете термина для этого, поэтому не можете найти его самостоятельно.
Для полноты (в отношении различных комментариев) ...
Как заявил Эрик, вы можете выполнить несколько строк кода:
varButtonClicked=newAction(()=>{MessageBox.Show("hi");MessageBox.Show("something else");// something more useful than another popup ;)});
Как сказал Тим, вы можете опустить Actionключевое слово
ActionButtonClicked=()=>MessageBox.Show("hi");ActionButtonClicked=()=>{// multiple lines of code};
Чтобы обратиться к комментарию Крайана относительно пустых круглых скобок, который представляет список параметров, которые вы хотите отправить в действие (в данном случае, ни одного) .
Если, например, вы хотите указать отображаемое сообщение, вы можете добавить «сообщение» в качестве параметра (обратите внимание, что я изменил Actionзначение на, чтобы указать один строковый параметр) :Action<string>
Action ButtonClicked = () => MessageBox.Show("hi");эквивалентен и IMO лучше (добавьте скобки, если хотите)
Тим С.
1
Также возможно, что действие будет разрешено более чем в одну строку кода.
Эрик Филипс
2
@CSharpie Я не уверен, что это предположение полезно для OP.
Эрик Филипс
2
@CSharpie Почему OP не мог использовать это WinForms?
vivat pisces
2
@CSharpie, я понимаю, о чем вы говорите. Если он действительно прикрепляет это к Button.Clickсобытию, а не сохраняет его в переменной, которую он случайно назвал ButtonClicked.
vivat pisces
51
В вашем случае вы хотите использовать delegate.
Давайте посмотрим, как работает делегат и как мы можем получить более простую форму, понимая его концепцию:
// Create a normal functionvoidOnButtonClick(){MessageBox.Show("Hello World!");}// Now we create a delegate called ButtonClickdelegatevoidButtonClick();
Видите ли, делегат принимает форму обычной функции, но без каких-либо аргументов (он может принимать любое количество аргументов, как и любой другой метод, но для простоты это не так).
Теперь давайте использовать то, что у нас есть; мы определим делегат так же, как и любую другую переменную:
Мы в основном создали новую переменную с именем ButtonClicked, которая имеет тип ButtonClick (который является делегатом) и при использовании будет выполнять метод в методе OnButtonClick ().
Чтобы использовать его, мы просто вызываем:ButtonClicked();
Итак, весь код будет таким:
delegatevoidButtonClick();voidOnButtonClick(){MessageBox.Show("Hello World!");}voidFoo(){ButtonClickButtonClicked=newButtonClick(OnButtonClick);ButtonClicked();// Execute the function.}
Отсюда мы можем перейти к лямбда-выражениям и посмотреть, как они могут быть полезны в вашей ситуации:
существует множество делегатов, уже определенных библиотеками .NET, например Action, которые не принимают никаких параметров и не возвращают значения. Он определяется как « public delegate void Action();
Вы всегда можете использовать его для своих нужд, вместо того, чтобы каждый раз определять нового делегата». Например, в предыдущем контексте вы могли просто написать
который бы сделал то же самое.
Теперь, когда вы увидели разные способы использования делегатов, давайте воспользуемся нашим первым лямбда-выражением. Лямбда-выражения - это анонимные функции; Итак, это обычные функции, но без имени. Они бывают следующих форм:
x =>DoSomethingWithX(x);(x)=>DoSomethingWithX(x);(x,y)=>DoSometingWithXY(x,y);()=>Console.WriteLine("I do not have parameters!");
В нашем случае у нас нет никаких параметров, поэтому мы будем использовать последнее выражение. Мы можем использовать это так же, как функцию OnButtonClick, но мы получаем то преимущество, что у нас нет именованной функции. Вместо этого мы можем сделать что-то вроде этого:
затем просто вызовите. ButtonClicked();Конечно, у вас также может быть многострочный код, но я не хочу вас больше запутывать. Хотя это выглядело бы так:
Вы также можете поиграть, например, вы можете выполнить такую функцию:
newAction(()=>MessageBox.Show("Hello World!"))();
Извините за длинный пост, надеюсь, он не слишком запутал :)
РЕДАКТИРОВАТЬ: я забыл упомянуть, что альтернативная форма, которая, хотя и не часто используется, может упростить понимание лямбда-выражений:
newAction(delegate(){Console.WriteLine("I am parameterless");})();
Также с помощью дженериков:
// Defines a delegate that has one parameter of type string. You could pass as many parameters as you want.newAction<string>(delegate(string x){Console.WriteLine(x);})("I am a string parameter!");
В свою очередь, вы можете использовать лямбда-выражения, но вам не нужно (но может в некоторых случаях) определять тип параметра, например, приведенный выше код можно просто записать как:
newAction<string>(x =>{Console.WriteLine(x);})("I am a string parameter!");
или:
newAction<string>(x =>Console.WriteLine(x))("I am a string parameter!");
EDIT2: Action<string>это представление public void delegate Action(string obj); Action<string,string>- это представление. public void delegate Action(string obj, string obj2);
В общем, Action<T>это представлениеpublic void delegate Action<T>(T obj);
EDIT3: Я знаю, что сообщение было здесь какое-то время, но я думаю, что это действительно круто, чтобы не упомянуть: вы можете сделать это, что в основном связано с вашим вопросом:
LazyКласс разработан специально для представления значения , которое не будет вычисляться , пока вы не попросите его. Вы создаете его, предоставляя метод, который определяет, как он должен быть построен, но он будет обрабатывать выполнение этого метода не более одного раза (даже при наличии нескольких потоков, запрашивающих значение) и просто возвращая уже созданное значение для любых дополнительных запросов:
var foo =newLazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));var result = foo.Value;
Помните, что это Lazyследует использовать для значений, требующих большой вычислительной мощности, и что вы не должны использовать их для взаимодействия (поскольку семантика .Valueзаключается в том, что он возвращает значение, подобное свойству, а не (интерактивное) действие). Вместо этого для таких действий следует использовать делегата.
Abel
1
@Abel Нет, это не для значений, требующих большой вычислительной мощности, это для любого значения, для которого вы хотели бы отложить инициализацию до тех пор, пока он не будет запрошен, и никогда не инициализировать это значение более одного раза. При этом значение Valueбудет использовано; это DialogResultполучено из окна сообщения. Основное различие между этим решением и использованием делегата заключается в том, следует ли повторно вычислять значение при каждом запросе или нет. Моя интерпретация требований заключалась в том, что это концептуальная инициализация значения, а не операция, которую нужно повторить.
Servy
Lazyможет быть легко использован неправильно. У него есть накладные расходы, поэтому использование его «просто» для отсрочки небольшой задачи вызовет больше накладных расходов, чем получит. Отображение ящиков сообщений из свойства - это (imo) плохая практика в целом, независимо от Lazy. Кстати, из MSDN цитирую: «Используйте ленивую инициализацию, чтобы отложить создание большого или ресурсоемкого объекта» . Вы можете не согласиться с этим, но изначально он был разработан именно для этого.
Abel
1
@Abel Накладные расходы на производительность Lazyв таком контексте, безусловно, незначительны; он будет бледнеть по сравнению со временем, проведенным в ожидании, пока человек нажмет на окно сообщения. В основном это сводится к реальным требованиям базового приложения; расплывчатость вопроса делает невозможным объективно правильный ответ. Это одна из интерпретаций вопроса. Что касается того, что делать много работы в приобретателе собственности плохо; видимо вы принципиально против всего дизайна Lazy. Добро пожаловать на это мнение.
Servy
Извините, вы, должно быть, неправильно меня поняли. Конечно, MessageBox накладные расходы незначительны (я бы просто не использовал UI внутри свойства). Я имел в виду небольшие задачи в целом (например, отсрочку 2 + 3 * 4 / i), когда накладные расходы на создание закрытия больше, чем сам расчет. И я думаю, что полностью согласен Lazy, на самом деле мы часто используем его в F # (немного меньше в C #), и мы на собственном горьком опыте узнали, что вы должны быть осторожны с этим, особенно в отношении производительности.
Abel
4
Как я читаю ваш вопрос, это в контексте элементов управления графическим интерфейсом?
Вы можете назначить код C # переменной, скомпилировать его во время выполнения и запустить код:
Напишите свой код:
// Assign C# code to the code variable.string code =@"
using System;
namespace First
{
public class Program
{
public static void Main()
{
"+"Console.WriteLine(\"Hello, world!\");"+@"
}
}
}
";
Ответы:
Вы можете назначить это
Action
так:Тогда назовите это:
Для полноты (в отношении различных комментариев) ...
Как заявил Эрик, вы можете выполнить несколько строк кода:
Как сказал Тим, вы можете опустить
Action
ключевое словоЧтобы обратиться к комментарию Крайана относительно пустых круглых скобок, который представляет список параметров, которые вы хотите отправить в действие (в данном случае, ни одного) .
Если, например, вы хотите указать отображаемое сообщение, вы можете добавить «сообщение» в качестве параметра (обратите внимание, что я изменил
Action
значение на, чтобы указать один строковый параметр) :Action<string>
источник
Action ButtonClicked = () => MessageBox.Show("hi");
эквивалентен и IMO лучше (добавьте скобки, если хотите)WinForms
?Button.Click
событию, а не сохраняет его в переменной, которую он случайно назвалButtonClicked
.В вашем случае вы хотите использовать
delegate
.Давайте посмотрим, как работает делегат и как мы можем получить более простую форму, понимая его концепцию:
Видите ли, делегат принимает форму обычной функции, но без каких-либо аргументов (он может принимать любое количество аргументов, как и любой другой метод, но для простоты это не так).
Теперь давайте использовать то, что у нас есть; мы определим делегат так же, как и любую другую переменную:
Мы в основном создали новую переменную с именем ButtonClicked, которая имеет тип ButtonClick (который является делегатом) и при использовании будет выполнять метод в методе OnButtonClick ().
Чтобы использовать его, мы просто вызываем:
ButtonClicked();
Итак, весь код будет таким:
Отсюда мы можем перейти к лямбда-выражениям и посмотреть, как они могут быть полезны в вашей ситуации:
существует множество делегатов, уже определенных библиотеками .NET, например Action, которые не принимают никаких параметров и не возвращают значения. Он определяется как «
public delegate void Action();
Вы всегда можете использовать его для своих нужд, вместо того, чтобы каждый раз определять нового делегата». Например, в предыдущем контексте вы могли просто написать
который бы сделал то же самое.
Теперь, когда вы увидели разные способы использования делегатов, давайте воспользуемся нашим первым лямбда-выражением. Лямбда-выражения - это анонимные функции; Итак, это обычные функции, но без имени. Они бывают следующих форм:
В нашем случае у нас нет никаких параметров, поэтому мы будем использовать последнее выражение. Мы можем использовать это так же, как функцию OnButtonClick, но мы получаем то преимущество, что у нас нет именованной функции. Вместо этого мы можем сделать что-то вроде этого:
или даже проще,
затем просто вызовите.
ButtonClicked();
Конечно, у вас также может быть многострочный код, но я не хочу вас больше запутывать. Хотя это выглядело бы так:Вы также можете поиграть, например, вы можете выполнить такую функцию:
Извините за длинный пост, надеюсь, он не слишком запутал :)
РЕДАКТИРОВАТЬ: я забыл упомянуть, что альтернативная форма, которая, хотя и не часто используется, может упростить понимание лямбда-выражений:
Также с помощью дженериков:
В свою очередь, вы можете использовать лямбда-выражения, но вам не нужно (но может в некоторых случаях) определять тип параметра, например, приведенный выше код можно просто записать как:
или:
EDIT2:
Action<string>
это представлениеpublic void delegate Action(string obj);
Action<string,string>
- это представление.public void delegate Action(string obj, string obj2);
В общем,
Action<T>
это представлениеpublic void delegate Action<T>(T obj);
EDIT3: Я знаю, что сообщение было здесь какое-то время, но я думаю, что это действительно круто, чтобы не упомянуть: вы можете сделать это, что в основном связано с вашим вопросом:
или просто:
источник
Lazy
Класс разработан специально для представления значения , которое не будет вычисляться , пока вы не попросите его. Вы создаете его, предоставляя метод, который определяет, как он должен быть построен, но он будет обрабатывать выполнение этого метода не более одного раза (даже при наличии нескольких потоков, запрашивающих значение) и просто возвращая уже созданное значение для любых дополнительных запросов:источник
Lazy
следует использовать для значений, требующих большой вычислительной мощности, и что вы не должны использовать их для взаимодействия (поскольку семантика.Value
заключается в том, что он возвращает значение, подобное свойству, а не (интерактивное) действие). Вместо этого для таких действий следует использовать делегата.Value
будет использовано; этоDialogResult
получено из окна сообщения. Основное различие между этим решением и использованием делегата заключается в том, следует ли повторно вычислять значение при каждом запросе или нет. Моя интерпретация требований заключалась в том, что это концептуальная инициализация значения, а не операция, которую нужно повторить.Lazy
может быть легко использован неправильно. У него есть накладные расходы, поэтому использование его «просто» для отсрочки небольшой задачи вызовет больше накладных расходов, чем получит. Отображение ящиков сообщений из свойства - это (imo) плохая практика в целом, независимо отLazy
. Кстати, из MSDN цитирую: «Используйте ленивую инициализацию, чтобы отложить создание большого или ресурсоемкого объекта» . Вы можете не согласиться с этим, но изначально он был разработан именно для этого.Lazy
в таком контексте, безусловно, незначительны; он будет бледнеть по сравнению со временем, проведенным в ожидании, пока человек нажмет на окно сообщения. В основном это сводится к реальным требованиям базового приложения; расплывчатость вопроса делает невозможным объективно правильный ответ. Это одна из интерпретаций вопроса. Что касается того, что делать много работы в приобретателе собственности плохо; видимо вы принципиально против всего дизайнаLazy
. Добро пожаловать на это мнение.MessageBox
накладные расходы незначительны (я бы просто не использовал UI внутри свойства). Я имел в виду небольшие задачи в целом (например, отсрочку2 + 3 * 4 / i
), когда накладные расходы на создание закрытия больше, чем сам расчет. И я думаю, что полностью согласенLazy
, на самом деле мы часто используем его в F # (немного меньше в C #), и мы на собственном горьком опыте узнали, что вы должны быть осторожны с этим, особенно в отношении производительности.Как я читаю ваш вопрос, это в контексте элементов управления графическим интерфейсом?
Если это в WPF, взгляните на «правильный» способ обработки команд из элементов управления: http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
... но это может быть болью и излишним. В более простом общем случае вам может понадобиться обработчик событий, например:
С этим обработчиком событий можно обращаться разными способами. В приведенном выше примере используется анонимная функция, но вы также можете:
... точно так же, как вы просили, с функцией (или здесь «Действие», поскольку она возвращает void), назначенной как переменная.
источник
Вы можете назначить код C # переменной, скомпилировать его во время выполнения и запустить код:
Напишите свой код:
Создайте провайдер и параметры компилятора:
Определите параметры компилятора:
Скомпилировать сборку:
Проверить ошибки:
Получим сборку, тип и метод Main:
Запустить его:
Ссылка:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
источник