+1 pela rara combinação de ser novo na codificação e fazer uma boa pergunta: você entende o que deseja fazer e o explica bem, simplesmente não conhece o termo para ele e não pode encontrá-lo sozinho.
stackoverflow.com/questions/6187944/… verifique isso, acho que há explanações suficientes que você precisará. Asp funciona quase como winforms nesse assunto.
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:
varButtonClicked=newAction(()=>{MessageBox.Show("hi");MessageBox.Show("something else");// something more useful than another popup ;)});
Como Tim afirmou, você pode omitir a Actionpalavra - chave
ActionButtonClicked=()=>MessageBox.Show("hi");ActionButtonClicked=()=>{// 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 Actionpara para especificar um único parâmetro de string) :Action<string>
Action ButtonClicked = () => MessageBox.Show("hi");é equivalente e IMO mais agradável (adicionar parênteses se você preferir)
Tim S.
1
Também é possível que a ação resolva para mais de uma única linha de código.
Erik Philips
2
@ CSharpie Não tenho certeza de que fazer essa suposição seja útil para o OP.
Erik Philips
2
@CSharpie Por que o OP não pôde usar isso WinForms?
vivat peixes
2
@ CSharpie eu vejo o que você está dizendo. Se ele está realmente anexando isso a um Button.Clickevento, e não o armazenando em uma variável que ele nomeou ButtonClicked.
vivat peixes
51
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 functionvoidOnButtonClick(){MessageBox.Show("Hello World!");}// Now we create a delegate called ButtonClickdelegatevoidButtonClick();
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:
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:
delegatevoidButtonClick();voidOnButtonClick(){MessageBox.Show("Hello World!");}voidFoo(){ButtonClickButtonClicked=newButtonClick(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
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:
Você também pode brincar, por exemplo, pode executar uma função como esta:
newAction(()=>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:
newAction(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.newAction<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:
newAction<string>(x =>{Console.WriteLine(x);})("I am a string parameter!");
ou:
newAction<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:
A Lazyclasse 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 =newLazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));var result = foo.Value;
Lembre-se de que Lazydeve 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.
Abel
1
@Abel Não, não se trata de valores que exigem muito poder de processamento, mas de qualquer valor que você queira adiar a inicialização até que seja solicitada, sem nunca inicializar esse valor mais de uma vez. Aqui o valor de Valueé usado; é o DialogResultrecebido 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.
Servy
Lazypode 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.
Abel
1
@Abel A sobrecarga de desempenho Lazyem 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.
Servy
Desculpe, você deve ter me entendido mal. Certamente, com 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.
Abel
4
Do jeito que estou lendo sua pergunta, isso é no contexto dos controles da GUI?
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!\");"+@"
}
}
}
";
Respostas:
Você pode atribuí-lo a um
Action
assim:Então chame-o:
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:
Como Tim afirmou, você pode omitir a
Action
palavra - chavePara 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>
fonte
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 nomeouButtonClicked
.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:
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:
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:
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
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:
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:
ou ainda mais fácil,
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:Você também pode brincar, por exemplo, pode executar uma função como esta:
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:
Além disso, usando genéricos:
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:
ou:
EDIT2:
Action<string>
é uma representação depublic void delegate Action(string obj);
Action<string,string>
é uma representação depublic 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:
ou simplesmente:
fonte
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:fonte
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; é oDialogResult
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 deLazy
. 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 deLazy
. 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 adiar2 + 3 * 4 / i
), em que a sobrecarga de criação do fechamento é maior que o próprio cálculo. E acho que aceito totalmenteLazy
, 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:
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:
... exatamente como você estava perguntando, com uma função (ou aqui, "Ação", pois retorna nula) atribuída como uma variável.
fonte
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:
Crie o provedor e os parâmetros do compilador:
Defina parâmetros do compilador:
Compilar montagem:
Verifique os erros:
Obtenha montagem, tipo e o método Main:
Executá-lo:
Referência:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
fonte