Возможно ли сделать переменную и присвоить ей строку кода, например:
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
};
Чтобы указать комментарий KRyan относительно пустых круглых скобок, который представляет список параметров, которые вы хотите отправить в действие (в этом случае нет).
Если, например, вы хотите указать отображаемое сообщение, вы можете добавить "сообщение" в качестве параметра (обратите внимание, что я изменил Action
на Action<string>
, чтобы указать один строковый параметр):
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
В вашем случае вы хотите использовать 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!"))();
Извините за длинный пост, надеюсь, что это не было слишком запутанным:)
EDIT: Я забыл упомянуть, что альтернативная форма, которая, хотя и не часто используется, может облегчить понимание лямбда-выражений:
new Action(delegate() {
Console.WriteLine("I am parameterless");
})();
Также, используя generics:
// 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;
Как я читаю ваш вопрос, это в контексте элементов управления графическим интерфейсом?
Если это в 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), назначенной как переменная.
Вы можете назначить код С# переменной, скомпилировать ее во время выполнения и запустить код:
Введите код:
// 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