web-dev-qa-db-fra.com

Attribution de code à une variable

Est-il possible de créer une variable et de lui affecter une ligne de code, telle que:

ButtonClicked = (MessageBox.Show("Hello, World!"));

... donc quand j'utilise la variable, elle exécutera la ligne de code.

124
user3539891

Vous pouvez l'attribuer à un Action comme ceci:

var ButtonClicked = new Action(() => MessageBox.Show("hi"));

Appelez-le ensuite:

ButtonClicked();

Pour être complet (en ce qui concerne les différents commentaires) ...

Comme l'a déclaré Erik, vous pouvez exécuter plusieurs lignes de code:

var ButtonClicked = new Action(() =>
{
    MessageBox.Show("hi");

    MessageBox.Show("something else");  // something more useful than another popup ;)
});

Comme l'a indiqué Tim, vous pouvez omettre le mot clé Action

Action ButtonClicked = () => MessageBox.Show("hi");

Action ButtonClicked = () =>
{
    // multiple lines of code
};

Pour répondre au commentaire de KRyan, concernant les parenthèses vides, qui représente la liste des paramètres que vous souhaitez pouvoir envoyer à l'action (dans ce cas, aucun) .

Si, par exemple, vous souhaitez spécifier le message à afficher, vous pouvez ajouter "message" comme paramètre (notez que j'ai changé Action à Action<string> afin de spécifier un paramètre de chaîne unique) :

Action<string> ButtonClicked = (message) => MessageBox.Show(message);

ButtonClicked("hello world!");
89
Grant

Dans votre cas, vous souhaitez utiliser un delegate.

Voyons comment fonctionne un délégué et comment nous pouvons accéder à une forme plus simple en comprenant son concept:

// Create a normal function
void OnButtonClick()
{
    MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();

Vous voyez, le délégué prend la forme d'une fonction normale mais sans aucun argument (cela peut prendre n'importe quelle quantité d'arguments comme n'importe quelle autre méthode, mais pour des raisons de simplicité, ce n'est pas le cas).

Maintenant, utilisons ce que nous avons; nous définirons le délégué comme nous définissons toute autre variable:

ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);

Nous avons essentiellement créé une nouvelle variable appelée ButtonClicked, qui a un type de ButtonClick (qui est un délégué) et qui, lorsqu'elle est utilisée, exécutera la méthode dans la méthode OnButtonClick ().
Pour l'utiliser, nous appelons simplement: ButtonClicked();

Donc, tout le code serait:

delegate void ButtonClick();

void OnButtonClick()
{
    MessageBox.Show("Hello World!");
}

void Foo()
{
    ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
    ButtonClicked(); // Execute the function.
}  

À partir d'ici, nous pouvons passer aux expressions lambda et voir comment elles pourraient être utiles dans votre situation:
Il existe de nombreux délégués déjà définis par les bibliothèques .NET, dont certains comme Action, qui n'acceptent aucun paramètre et ne renvoient aucune valeur. Il est défini comme public delegate void Action();
Vous pouvez toujours l'utiliser selon vos besoins au lieu de définir un nouveau délégué à chaque fois. Dans le contexte précédent par exemple, vous auriez pu écrire

Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();

qui aurait fait de même.
Maintenant que vous avez vu différentes façons d'utiliser les délégués, utilisons notre première expression lambda. Les expressions lambda sont des fonctions anonymes; ce sont donc des fonctions normales mais sans nom. Ils sont de ces formes:

x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");

Dans notre cas, nous n'avons aucun paramètre, nous allons donc utiliser la dernière expression. Nous pouvons l'utiliser comme la fonction OnButtonClick, mais nous avons l'avantage de ne pas avoir de fonction nommée. Nous pouvons plutôt faire quelque chose comme ceci:

Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );

ou encore plus facile,

Action ButtonClicked = () => MessageBox.Show("Hello World!");

puis appelez simplement ButtonClicked(); Bien sûr, vous pouvez également avoir plusieurs lignes de code, mais je ne veux pas vous embrouiller davantage. Cela ressemblerait à ceci:

Action ButtonClicked = () => 
{
    MessageBox.Show("Hello World!");
};
ButtonClicked();

Vous pouvez également jouer, par exemple, vous pouvez exécuter une fonction comme celle-ci:

new Action(() => MessageBox.Show("Hello World!"))();

Désolé pour le long post, j'espère que ce n'était pas trop déroutant :)

EDIT: J'ai oublié de mentionner qu'une forme alternative qui, même si elle n'est pas souvent utilisée, pourrait rendre les expressions lambda plus faciles à comprendre:

new Action(delegate() {
    Console.WriteLine("I am parameterless");
})();

En outre, en utilisant des génériques:

// 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!");

À son tour, vous pouvez utiliser des expressions lambda, mais vous n'avez pas besoin (mais dans certains cas) de définir le type du paramètre, par exemple, le code ci-dessus peut simplement être écrit comme suit:

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> Est une représentation de public void delegate Action(string obj);
Action<string,string> Est une représentation de public void delegate Action(string obj, string obj2);
En général, Action<T> Est une représentation de public void delegate Action<T>(T obj);

EDIT3: Je sais que le message est ici depuis un certain temps, mais je pense que c'est vraiment cool de ne pas le mentionner: vous pouvez le faire, ce qui est principalement lié à votre question:

dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");

ou simplement:

Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
51
user3439065

La classe Lazy est spécialement conçue pour représenter une valeur qui ne sera calculée que lorsque vous la demanderez. Vous le construisez en fournissant une méthode qui définit comment il doit être construit, mais il gérera l'exécution de cette méthode pas plus d'une fois (même face à plusieurs threads demandant la valeur) et en renvoyant simplement la valeur déjà construite pour toute demande supplémentaire:

var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));

var result = foo.Value;
7
Servy

La façon dont je lis votre question, c'est dans le contexte des contrôles GUI?

Si c'est dans WPF, jetez un œil à la "bonne" façon de gérer les commandes des contrôles: http://msdn.Microsoft.com/en-us/library/ms752308 (v = vs.110). aspx

... mais cela peut être une douleur et une exagération. Pour un cas général plus simple, vous cherchez peut-être un gestionnaire d'événements, comme:

myButton.Click += (o, e) => MessageBox.Show("Hello, World!");

Ce gestionnaire d'événements peut être géré de différentes manières. L'exemple ci-dessus utilise une fonction anonyme, mais vous pouvez également faire:

Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);

... comme vous le demandiez, avec une fonction (ou ici, "Action", car elle renvoie void) assignée comme variable.

4
Zaccone

Vous pouvez affecter du code C # à une variable, le compiler au moment de l'exécution et exécuter le code:

  • Écrivez votre code:

    // Assign C# code to the code variable.
    string code = @"
    using System;
    
    namespace First
    {
        public class Program
        {
            public static void Main()
            {
                " +
                "Console.WriteLine(\"Hello, world!\");"
                + @"
            }
        }
    }
    ";
    
  • Créez le fournisseur et les paramètres du compilateur:

    CSharpCodeProvider provider = new CSharpCodeProvider();
    CompilerParameters parameters = new CompilerParameters();
    
  • Définissez les paramètres du compilateur:

    // 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;
    
  • Compiler l'assemblage:

    CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
    
  • Vérifiez les erreurs:

    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());
    }
    
  • Obtenez Assembly, tapez et la méthode Main:

    Assembly assembly = results.CompiledAssembly;
    Type program = Assembly.GetType("First.Program");
    MethodInfo main = program.GetMethod("Main");
    
  • Exécuter:

    main.Invoke(null, null);
    

Référence:

http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime

1
Amir Saniyan