Можно ли создать переменную и присвоить ей строку кода, например:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... поэтому, когда я использую переменную, она выполнит строку кода.
Можно ли создать переменную и присвоить ей строку кода, например:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... поэтому, когда я использую переменную, она выполнит строку кода.
Ответы:
Вы можете назначить это Action
так:
var ButtonClicked = new Action(() => MessageBox.Show("hi"));
Тогда назовите это:
ButtonClicked();
Для полноты (в отношении различных комментариев) ...
Как заявил Эрик, вы можете выполнить несколько строк кода:
var ButtonClicked = new Action(() =>
{
MessageBox.Show("hi");
MessageBox.Show("something else"); // something more useful than another popup ;)
});
Как сказал Тим, вы можете опустить Action
ключевое слово
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// multiple lines of code
};
Чтобы обратиться к комментарию Крайана относительно пустых круглых скобок, который представляет список параметров, которые вы хотите отправить в действие (в данном случае, ни одного) .
Если, например, вы хотите указать отображаемое сообщение, вы можете добавить «сообщение» в качестве параметра (обратите внимание, что я изменил Action
значение на, чтобы указать один строковый параметр) :Action<string>
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
Action ButtonClicked = () => MessageBox.Show("hi");
эквивалентен и IMO лучше (добавьте скобки, если хотите)
WinForms
?
Button.Click
событию, а не сохраняет его в переменной, которую он случайно назвал ButtonClicked
.
В вашем случае вы хотите использовать delegate
.
Давайте посмотрим, как работает делегат и как мы можем получить более простую форму, понимая его концепцию:
// Create a normal function
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();
Видите ли, делегат принимает форму обычной функции, но без каких-либо аргументов (он может принимать любое количество аргументов, как и любой другой метод, но для простоты это не так).
Теперь давайте использовать то, что у нас есть; мы определим делегат так же, как и любую другую переменную:
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
Мы в основном создали новую переменную с именем ButtonClicked, которая имеет тип ButtonClick (который является делегатом) и при использовании будет выполнять метод в методе OnButtonClick ().
Чтобы использовать его, мы просто вызываем:ButtonClicked();
Итак, весь код будет таким:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
Отсюда мы можем перейти к лямбда-выражениям и посмотреть, как они могут быть полезны в вашей ситуации:
существует множество делегатов, уже определенных библиотеками .NET, например Action, которые не принимают никаких параметров и не возвращают значения. Он определяется как « public delegate void Action();
Вы всегда можете использовать его для своих нужд, вместо того, чтобы каждый раз определять нового делегата». Например, в предыдущем контексте вы могли просто написать
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
который бы сделал то же самое.
Теперь, когда вы увидели разные способы использования делегатов, давайте воспользуемся нашим первым лямбда-выражением. Лямбда-выражения - это анонимные функции; Итак, это обычные функции, но без имени. Они бывают следующих форм:
x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");
В нашем случае у нас нет никаких параметров, поэтому мы будем использовать последнее выражение. Мы можем использовать это так же, как функцию OnButtonClick, но мы получаем то преимущество, что у нас нет именованной функции. Вместо этого мы можем сделать что-то вроде этого:
Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );
или даже проще,
Action ButtonClicked = () => MessageBox.Show("Hello World!");
затем просто вызовите. ButtonClicked();
Конечно, у вас также может быть многострочный код, но я не хочу вас больше запутывать. Хотя это выглядело бы так:
Action ButtonClicked = () =>
{
MessageBox.Show("Hello World!");
};
ButtonClicked();
Вы также можете поиграть, например, вы можете выполнить такую функцию:
new Action(() => MessageBox.Show("Hello World!"))();
Извините за длинный пост, надеюсь, он не слишком запутал :)
РЕДАКТИРОВАТЬ: я забыл упомянуть, что альтернативная форма, которая, хотя и не часто используется, может упростить понимание лямбда-выражений:
new Action(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.
new Action<string>(delegate(string x) {
Console.WriteLine(x);
})("I am a string parameter!");
В свою очередь, вы можете использовать лямбда-выражения, но вам не нужно (но может в некоторых случаях) определять тип параметра, например, приведенный выше код можно просто записать как:
new Action<string>(x => {
Console.WriteLine(x);
})("I am a string parameter!");
или:
new Action<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: Я знаю, что сообщение было здесь какое-то время, но я думаю, что это действительно круто, чтобы не упомянуть: вы можете сделать это, что в основном связано с вашим вопросом:
dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");
или просто:
Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
Lazy
Класс разработан специально для представления значения , которое не будет вычисляться , пока вы не попросите его. Вы создаете его, предоставляя метод, который определяет, как он должен быть построен, но он будет обрабатывать выполнение этого метода не более одного раза (даже при наличии нескольких потоков, запрашивающих значение) и просто возвращая уже созданное значение для любых дополнительных запросов:
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
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
... но это может быть болью и излишним. В более простом общем случае вам может понадобиться обработчик событий, например:
myButton.Click += (o, e) => MessageBox.Show("Hello, World!");
С этим обработчиком событий можно обращаться разными способами. В приведенном выше примере используется анонимная функция, но вы также можете:
Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);
... точно так же, как вы просили, с функцией (или здесь «Действие», поскольку она возвращает void), назначенной как переменная.
Вы можете назначить код 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!\");"
+ @"
}
}
}
";
Создайте провайдер и параметры компилятора:
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Определите параметры компилятора:
// Reference to System.Drawing library
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
// True - memory generation, false - external file generation
parameters.GenerateInMemory = true;
// True - exe file generation, false - dll file generation
parameters.GenerateExecutable = true;
Скомпилировать сборку:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
Проверить ошибки:
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Получим сборку, тип и метод Main:
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
Запустить его:
main.Invoke(null, null);
Ссылка:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime