É possível criar uma variável e atribuir uma linha de código a ela, como:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... então, quando eu uso a variável, ela executa a linha de código.
É possível criar uma variável e atribuir uma linha de código a ela, como:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... então, quando eu uso a variável, ela executa a linha de código.
Respostas:
Você pode atribuí-lo a um Action
assim:
var ButtonClicked = new Action(() => MessageBox.Show("hi"));
Então chame-o:
ButtonClicked();
Por uma questão de integridade (em relação aos vários comentários) ...
Como Erik afirmou, você pode executar várias linhas de código:
var ButtonClicked = new Action(() =>
{
MessageBox.Show("hi");
MessageBox.Show("something else"); // something more useful than another popup ;)
});
Como Tim afirmou, você pode omitir a Action
palavra - chave
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// multiple lines of code
};
Para abordar o comentário do KRyan, sobre os parênteses vazios, que representa a lista de parâmetros que você deseja enviar para a Ação (neste caso, nenhum) .
Se, por exemplo, você quiser especificar a mensagem a ser exibida, poderá adicionar "message" como parâmetro (observe que mudei Action
para para especificar um único parâmetro de string) :Action<string>
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
Action ButtonClicked = () => MessageBox.Show("hi");
é equivalente e IMO mais agradável (adicionar parênteses se você preferir)
WinForms
?
Button.Click
evento, e não o armazenando em uma variável que ele nomeou ButtonClicked
.
No seu caso, você deseja usar a delegate
.
Vamos ver como um delegado funciona e como podemos chegar a uma forma mais fácil, entendendo seu conceito:
// Create a normal function
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();
Veja bem, o delegado assume a forma de uma função normal, mas sem argumentos (poderia levar qualquer quantidade de argumentos como qualquer outro método, mas por uma questão de simplicidade, não).
Agora, vamos usar o que temos; definiremos o delegado da mesma maneira que definimos qualquer outra variável:
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
Basicamente, criamos uma nova variável chamada ButtonClicked, que possui um tipo de ButtonClick (que é um delegado) e que, quando usado, executará o método no método OnButtonClick ().
Para usá-lo, simplesmente chamamos:ButtonClicked();
Portanto, o código inteiro seria:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
A partir daqui, podemos passar para expressões lambda e ver como elas podem ser úteis na sua situação:
Existem muitos delegados já definidos pelas bibliotecas .NET, com alguns como Action, que não aceitam nenhum parâmetro e não retornam um valor. É definido como public delegate void Action();
Você sempre pode usá-lo de acordo com suas necessidades, em vez da necessidade de definir um novo delegado sempre. No contexto anterior, por exemplo, você poderia escrever
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
o que teria feito o mesmo.
Agora que você viu maneiras diferentes de usar delegados, vamos usar nossa primeira expressão lambda. Expressões lambda são funções anônimas; portanto, são funções normais, mas sem nome. Eles são dessas formas:
x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");
No nosso caso, como não temos parâmetros, usaremos a última expressão. Podemos usar isso como a função OnButtonClick, mas temos a vantagem de não ter uma função nomeada. Em vez disso, podemos fazer algo assim:
Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );
ou ainda mais fácil,
Action ButtonClicked = () => MessageBox.Show("Hello World!");
então simplesmente chame ButtonClicked();
Claro que você também pode ter várias linhas de código, mas não quero confundir mais. Seria assim:
Action ButtonClicked = () =>
{
MessageBox.Show("Hello World!");
};
ButtonClicked();
Você também pode brincar, por exemplo, pode executar uma função como esta:
new Action(() => MessageBox.Show("Hello World!"))();
Desculpe pelo longo post, espero que não tenha sido muito confuso :)
EDIT: Esqueci de mencionar que uma forma alternativa que, embora não seja usada com frequência, poderia facilitar a compreensão das expressões lambda:
new Action(delegate() {
Console.WriteLine("I am parameterless");
})();
Além disso, usando genéricos:
// 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!");
Por sua vez, você pode usar expressões lambda, mas não precisa (mas pode em alguns casos) definir o tipo do parâmetro, por exemplo, o código acima pode ser simplesmente escrito como:
new Action<string>(x => {
Console.WriteLine(x);
})("I am a string parameter!");
ou:
new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");
EDIT2:
Action<string>
é uma representação de public void delegate Action(string obj);
Action<string,string>
é uma representação de public void delegate Action(string obj, string obj2);
Em geral, Action<T>
é uma representação depublic void delegate Action<T>(T obj);
EDIT3: Eu sei que o post está aqui há um tempo, mas acho que é muito legal não mencionar: você pode fazer isso, principalmente relacionado à sua pergunta:
dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");
ou simplesmente:
Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
A Lazy
classe foi projetada especificamente para representar um valor que não será calculado até que você solicite. Você o constrói fornecendo um método que define como ele deve ser construído, mas ele manipula a execução desse método não mais de uma vez (mesmo diante de vários encadeamentos que solicitam o valor) e simplesmente retorna o valor já construído para quaisquer solicitações adicionais:
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
Lazy
deve ser usado para valores que exijam muito poder de processamento e que você não deve usá-los para interação (porque a semântica .Value
é que ele retorna um valor, semelhante a uma propriedade, e não uma ação (interativa)). Um delegado deve ser usado para essas ações.
Value
é usado; é o DialogResult
recebido de mostrar a caixa de mensagem. A principal diferença entre essa solução e o uso de um representante é se o valor deve ser recalculado sempre que solicitado ou não. Minha interpretação dos requisitos foi que isso está inicializando conceitualmente um valor, não uma operação a ser repetida.
Lazy
pode ser facilmente usado incorretamente. Ele tem sobrecarga de si mesmo, usá-lo "apenas" para adiar uma pequena tarefa invocará mais sobrecarga do que ganha. Mostrar caixas de mensagens de uma propriedade é (imo) prática recomendada em geral, independentemente de Lazy
. Btw, do MSDN, cito: "Use a inicialização lenta para adiar a criação de um objeto grande ou com muitos recursos" . Você pode discordar disso, mas foi para isso que foi projetado originalmente.
Lazy
em um contexto como esse é certamente insignificante; ficará pálido em comparação com o tempo gasto esperando que um humano clique em uma caixa de mensagem. Isso se resume principalmente aos requisitos reais do aplicativo subjacente; a imprecisão da pergunta torna impossível uma resposta objetivamente correta. Esta é uma interpretação da questão. Quanto a fazer muito trabalho em um getter de propriedade ser ruim; aparentemente você é fundamentalmente contrário a todo o design de Lazy
. Você é bem-vindo a essa opinião.
MessageBox
a sobrecarga é insignificante (eu não usaria a interface do usuário dentro de uma propriedade). Eu quis dizer pequenas tarefas em geral (como adiar 2 + 3 * 4 / i
), em que a sobrecarga de criação do fechamento é maior que o próprio cálculo. E acho que aceito totalmente Lazy
, na verdade, usamos muito em F # (um pouco menos em C #) e aprendemos da maneira mais difícil que você precisa para ter cuidado com isso, esp. em relação ao desempenho.
Do jeito que estou lendo sua pergunta, isso é no contexto dos controles da GUI?
Se isso estiver no WPF, consulte a maneira "correta" de manipular comandos de controles: http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
... mas isso pode ser uma dor e um exagero. Para um caso geral mais simples, você pode estar procurando um manipulador de eventos, como:
myButton.Click += (o, e) => MessageBox.Show("Hello, World!");
Esse manipulador de eventos pode ser tratado de várias maneiras. O exemplo acima usa uma função anônima, mas você também pode:
Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);
... exatamente como você estava perguntando, com uma função (ou aqui, "Ação", pois retorna nula) atribuída como uma variável.
Você pode atribuir código C # a uma variável, compilando-o em tempo de execução e executando o código:
Escreva seu código:
// Assign C# code to the code variable.
string code = @"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ @"
}
}
}
";
Crie o provedor e os parâmetros do compilador:
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Defina parâmetros do compilador:
// 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;
Compilar montagem:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
Verifique os erros:
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());
}
Obtenha montagem, tipo e o método Main:
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
Executá-lo:
main.Invoke(null, null);
Referência:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime