C # 'da Eylem Temsilcisi Kullanımları [kapalı]


132

Onlar hakkında daha fazla şey öğrenmek ve nerede yararlı olabileceklerini düşünmek umuduyla C #'daki Eylem Delegeleri ile birlikte çalışıyordum.

Eylem Temsilcisini kullanan oldu mu ve öyleyse neden? veya yararlı olabileceği bazı örnekler verebilir misiniz?

Yanıtlar:


25

MSDN diyor:

Bu temsilci, dizi veya listenin her öğesinde bir eylem gerçekleştirmek için Array.ForEach yöntemi ve List.ForEach yöntemi tarafından kullanılır.

Bunun dışında, herhangi bir değer döndürmeden 1-3 parametre alan genel bir temsilci olarak kullanabilirsiniz.


Action'ın bu çok parametreli sürümlerini hiç fark etmemiştim. Teşekkürler.
mackenir

114

İşte Eylem temsilcisinin kullanışlılığını gösteren küçük bir örnek

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Action<String> print = new Action<String>(Program.Print);

        List<String> names = new List<String> { "andrew", "nicole" };

        names.ForEach(print);

        Console.Read();
    }

    static void Print(String s)
    {
        Console.WriteLine(s);
    }
}

Foreach yönteminin ad koleksiyonunu yinelediğine ve yöntemi koleksiyonun printher üyesine karşı yürüttüğüne dikkat edin . Bu, daha işlevsel bir programlama stiline doğru ilerlerken, biz C # geliştiricileri için biraz paradigma değişikliği. (Arkasındaki bilgisayar bilimi hakkında daha fazla bilgi için şunu okuyun: http://en.wikipedia.org/wiki/Map_(higher-order_function) .

Şimdi, C # 3 kullanıyorsanız, aşağıdaki gibi bir lambda ifadesiyle bunu biraz yukarı kaydırabilirsiniz:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<String> names = new List<String> { "andrew", "nicole" };

        names.ForEach(s => Console.WriteLine(s));

        Console.Read();
    }
}

68

Yapabileceğiniz şeylerden biri, anahtarınız varsa:

switch(SomeEnum)
{
  case SomeEnum.One:
      DoThings(someUser);
      break;
  case SomeEnum.Two:
      DoSomethingElse(someUser);
      break;
}

Ve eylemlerin gücüyle bu anahtarı bir sözlüğe dönüştürebilirsiniz:

Dictionary<SomeEnum, Action<User>> methodList = 
    new Dictionary<SomeEnum, Action<User>>()

methodList.Add(SomeEnum.One, DoSomething);
methodList.Add(SomeEnum.Two, DoSomethingElse); 

...

methodList[SomeEnum](someUser);

Ya da bu kadar ileri gidebilirsin:

SomeOtherMethod(Action<User> someMethodToUse, User someUser)
{
    someMethodToUse(someUser);
}  

....

var neededMethod = methodList[SomeEnum];
SomeOtherMethod(neededMethod, someUser);

Sadece birkaç örnek. Elbette daha belirgin kullanım Linq uzatma yöntemleri olacaktır.


Harika, bence bu bir karar tablosu olarak kullanılabilir.
Biswanath

3
Güzel - bu bir yeniden düzenleme modelidir "Koşullu yerine Polimorfizm". refactoring.com/catalog/replaceConditionalWithPolymorphism.html
David Robbins

16

Kısa olay işleyicileri için eylemleri kullanabilirsiniz:

btnSubmit.Click += (sender, e) => MessageBox.Show("You clicked save!");

Bunları uzun olanlar için de kullanabilirsiniz; btnSubmit.Click + = (gönderen, e) => {MessageBox.Show ("Kaydet'e tıkladınız!"); MessageBox.Show ("Gerçekten yaptın!"); };
tdgtyugdyugdrugdr

15

Eylem temsilcisini bir projede bir kez böyle kullandım:

private static Dictionary<Type, Action<Control>> controldefaults = new Dictionary<Type, Action<Control>>() { 
            {typeof(TextBox), c => ((TextBox)c).Clear()},
            {typeof(CheckBox), c => ((CheckBox)c).Checked = false},
            {typeof(ListBox), c => ((ListBox)c).Items.Clear()},
            {typeof(RadioButton), c => ((RadioButton)c).Checked = false},
            {typeof(GroupBox), c => ((GroupBox)c).Controls.ClearControls()},
            {typeof(Panel), c => ((Panel)c).Controls.ClearControls()}
    };

tüm yaptığı bir kontrol türüne karşı bir eylemi (yöntem çağrısı) depolamaktır, böylece bir formdaki tüm kontrolleri oradaki varsayılanlara geri döndürebilirsiniz.


Güzel, büyük bir değişiklik değil ama keyedbyTypeCollection adında bir şey var, bunun diktiyoiner (tür, Nesne) etrafına sarıldığını düşünüyorum.
Biswanath

13

Action <> 'ın nasıl kullanıldığına dair bir örnek için.

Console.WriteLine tatmin edici bir imzaya sahiptir Action<string>.

    static void Main(string[] args)
    {
        string[] words = "This is as easy as it looks".Split(' ');

        // Passing WriteLine as the action
        Array.ForEach(words, Console.WriteLine);         
    }

Bu yardımcı olur umarım


11

Yasadışı Çapraz İş Parçacığı Çağrıları ile uğraşırken kullanıyorum Örneğin:

DataRow dr = GetRow();
this.Invoke(new Action(() => {
   txtFname.Text = dr["Fname"].ToString();
   txtLname.Text = dr["Lname"].ToString(); 
   txtMI.Text = dr["MI"].ToString();
   txtSSN.Text = dr["SSN"].ToString();
   txtSSN.ButtonsRight["OpenDialog"].Visible = true;
   txtSSN.ButtonsRight["ListSSN"].Visible = true;
   txtSSN.Focus();
}));

Çözüm için Reed Copsey SO kullanıcısı 65358'i belirtmeliyim. Cevaplarla ilgili tam sorum SO Soru 2587930


3

Bunu bir olay işleyicisinde geri arama olarak kullandım. Olayı yükselttiğimde, bir dizge alan bir yöntemi bir parametre olarak iletiyorum. Etkinliğin yükselmesi şuna benziyor:

SpecialRequest(this,
    new BalieEventArgs 
    { 
            Message = "A Message", 
            Action = UpdateMethod, 
            Data = someDataObject 
    });

Yöntem:

   public void UpdateMethod(string SpecialCode){ }

Olay Args'in sınıf bildirimi:

public class MyEventArgs : EventArgs
    {
        public string Message;
        public object Data;
        public Action<String> Action;
    }

Bu şekilde, verileri güncellemek için olay işleyicisinden geçen yöntemi bir parametre ile çağırabilirim. Bunu kullanıcıdan bazı bilgiler istemek için kullanıyorum.


Merhaba Sorskoot, UpdateMethod, MyEventArgs ve yeni BalieEventArgs'ın birlikte nasıl oynandığını genişletebilir misin? Mesaj UpdateMethod: UpdateMethod'a ("Bir Mesaj") aktarılan dizi mi? "SomeDataObject" nesnesini hangi yöntem kullanır? Şimdiden teşekkürler
surfmuggle

2

Testlerde çok sayıda Action delege işlevi kullanıyoruz. Varsayılan bir nesne oluşturmamız gerektiğinde ve daha sonra onu değiştirmemiz gerektiğinde. Küçük bir örnek verdim. Varsayılan kişi (John Doe) nesnesi oluşturmak için BuildPerson()function kullanıyoruz. Daha sonra Jane Doe'yi de ekliyoruz, ancak doğum tarihini, adını ve boyunu değiştiriyoruz.

public class Program
{
        public static void Main(string[] args)
        {
            var person1 = BuildPerson();

            Console.WriteLine(person1.Firstname);
            Console.WriteLine(person1.Lastname);
            Console.WriteLine(person1.BirthDate);
            Console.WriteLine(person1.Height);

            var person2 = BuildPerson(p =>
            {
                p.Firstname = "Jane";
                p.BirthDate = DateTime.Today;
                p.Height = 1.76;
            });

            Console.WriteLine(person2.Firstname);
            Console.WriteLine(person2.Lastname);
            Console.WriteLine(person2.BirthDate);
            Console.WriteLine(person2.Height);

            Console.Read();
        }

        public static Person BuildPerson(Action<Person> overrideAction = null)
        {
            var person = new Person()
            {
                Firstname = "John",
                Lastname = "Doe",
                BirthDate = new DateTime(2012, 2, 2)
            };

            if (overrideAction != null)
                overrideAction(person);

            return person;
        }
    }

    public class Person
    {
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public DateTime BirthDate { get; set; }
        public double Height { get; set; }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.