Code toewijzen aan een variabele

Is het mogelijk om een ​​variabele te maken en er een regel code aan toe te wijzen, zoals:

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

… dus als ik de variabele gebruik, wordt de coderegel uitgevoerd.


Antwoord 1, autoriteit 100%

Je zou het kunnen toewijzen aan een Actionzoals dit:

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

Noem het dan:

ButtonClicked();

Voor de volledigheid (met betrekking tot de verschillende opmerkingen)…

Zoals Erik al zei, je zou meerdere regels code kunnen uitvoeren:

var ButtonClicked = new Action(() =>
{
    MessageBox.Show("hi");
    MessageBox.Show("something else");  // something more useful than another popup ;)
});

Zoals Tim al zei, zou je het trefwoord Action

kunnen weglaten

Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
    // multiple lines of code
};

Om in te gaan op de opmerking van KRyan, met betrekking tot de lege haakjes, die de lijst met parameters vertegenwoordigt die u naar de actie wilt kunnen sturen (in dit geval geen).

Als u bijvoorbeeld het bericht wilt specificeren dat moet worden weergegeven, kunt u “bericht” als parameter toevoegen (merk op dat ikActionin heb gewijzigd Action<string>om een ​​enkele stringparameter te specificeren):

Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");

Antwoord 2, autoriteit 56%

In jouw geval wil je een delegategebruiken.

Laten we eens kijken hoe een afgevaardigde werkt en hoe we een eenvoudigere vorm kunnen krijgen door het concept ervan te begrijpen:

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

Zie je, de gedelegeerde heeft de vorm van een normale functie, maar zonder argumenten (het kan net als elke andere methode een willekeurig aantal argumenten hebben, maar omwille van de eenvoud doet het dat niet).

Laten we nu gebruiken wat we hebben; we definiëren de gedelegeerde net zoals we elke andere variabele definiëren:

ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);

We hebben in feite een nieuwe variabele gemaakt met de naam ButtonClicked, die een type ButtonClick heeft (wat een gedelegeerde is) en die bij gebruik de methode in de methode OnButtonClick() zal uitvoeren.
Om het te gebruiken roepen we gewoon: ButtonClicked();

Dus de hele code zou zijn:

delegate void ButtonClick();
void OnButtonClick()
{
    MessageBox.Show("Hello World!");
}
void Foo()
{
    ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
    ButtonClicked(); // Execute the function.
}  

Vanaf hier kunnen we naar lambda-expressies gaan en zien hoe ze in uw situatie nuttig kunnen zijn:
Er zijn al veel gedelegeerden gedefinieerd door .NET-bibliotheken, waarvan sommige zoals Action, die geen enkele parameter accepteren en geen waarde retourneren. Het is gedefinieerd als public delegate void Action();
U kunt het altijd gebruiken voor uw behoeften in plaats van elke keer een nieuwe gemachtigde te definiëren. In de vorige context had je bijvoorbeeld net

. kunnen schrijven

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

die hetzelfde zou hebben gedaan.
Nu je verschillende manieren hebt gezien om gedelegeerden te gebruiken, gaan we onze eerste lambda-uitdrukking gebruiken. Lambda-expressies zijn anonieme functies; het zijn dus normale functies, maar zonder naam. Ze zijn van die vormen:

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

In ons geval hebben we geen parameters, dus we zullen de laatste uitdrukking gebruiken. We kunnen dit net als de OnButtonClick-functie gebruiken, maar we hebben het voordeel dat we geen benoemde functie hebben. We kunnen in plaats daarvan iets als dit doen:

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

of nog makkelijker,

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

bel dan gewoon ButtonClicked();Natuurlijk kun je ook meerdere regels code gebruiken, maar ik wil je niet nog meer in verwarring brengen. Het zou er echter zo uitzien:

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

Je zou ook kunnen spelen, je kunt bijvoorbeeld een functie als deze uitvoeren:

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

Sorry voor het lange bericht, ik hoop dat het niet te verwarrend was 🙂

EDIT: ik vergat te vermelden dat een alternatieve vorm die, hoewel niet vaak gebruikt, lambda-uitdrukkingen begrijpelijker zou kunnen maken:

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

Ook generieke geneesmiddelen gebruiken:

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

U zou op uw beurt lambda-expressies kunnen gebruiken, maar u hoeft niet (maar kan in sommige gevallen) het type parameter te definiëren, de bovenstaande code kan bijvoorbeeld eenvoudig worden geschreven als:

new Action<string>(x => {
    Console.WriteLine(x);
})("I am a string parameter!");

of:

new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");

BEWERK2:
Action<string>is een weergave van public void delegate Action(string obj);
Action<string,string>is een weergave van public void delegate Action(string obj, string obj2);
Over het algemeen is Action<T>een weergave van public void delegate Action<T>(T obj);

BEWERKEN3:
Ik weet dat het bericht hier al een tijdje staat, maar ik denk dat dit echt cool is om niet te vermelden:
U kunt dit doen, wat grotendeels te maken heeft met uw vraag:

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

of gewoon:

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

Antwoord 3, autoriteit 8%

De Lazyis speciaal ontworpen om een ​​waarde weer te geven die pas wordt berekend als u erom vraagt. Je construeert het door een methode te bieden die definieert hoe het moet worden geconstrueerd, maar het zal die methode niet meer dan één keer uitvoeren (zelfs als er meerdere threads zijn die om de waarde vragen) en gewoon de reeds geconstrueerde waarde retourneren voor eventuele aanvullende verzoeken:

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

Antwoord 4, autoriteit 4%

Zoals ik uw vraag lees, is dit in de context van GUI-besturingselementen?

Als dit in WPF staat, kijk dan eens naar de “juiste” manier om commando’s van besturingselementen af ​​te handelen:
http://msdn.microsoft.com/en -us/library/ms752308(v=vs.110).aspx

…maar dat kan lastig en overdreven zijn. Voor een eenvoudiger algemeen geval zoekt u misschien naar een gebeurtenishandler, zoals:

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

Die event-handler kan op verschillende manieren worden afgehandeld. In het bovenstaande voorbeeld wordt een anonieme functie gebruikt, maar u kunt ook het volgende doen:

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

…net zoals je vroeg, met een functie (of hier, “Actie”, aangezien het void retourneert) toegewezen als een variabele.


Antwoord 5

U kunt C#-code aan een variabele toewijzen, deze tijdens runtime compileren en de code uitvoeren:

  • Schrijf je 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!\");"
                + @"
            }
        }
    }
    ";
    
  • Maak de provider en parameters van de compiler:

    CSharpCodeProvider provider = new CSharpCodeProvider();
    CompilerParameters parameters = new CompilerParameters();
    
  • Definieer parameters van de compiler:

    // 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;
    
  • Samenstelling samenstellen:

    CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
    
  • Controleer fouten:

    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());
    }
    
  • Verkrijg samenstelling, type en de hoofdmethode:

    Assembly assembly = results.CompiledAssembly;
    Type program = assembly.GetType("First.Program");
    MethodInfo main = program.GetMethod("Main");
    
  • Voer het uit:

    main.Invoke(null, null);
    

Referentie:

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

Other episodes