Обновление примера событий C # 2.0, чтобы быть идиоматическим с C # 3.5? - PullRequest
1 голос
/ 05 мая 2010

У меня есть короткий пример событий из .NET 2.0, который я использовал в качестве ориентира некоторое время. Сейчас мы обновляемся до 3.5, и мне не совсем понятен самый идиоматический способ сделать что-то. Как обновится этот простой пример событий, чтобы отразить идиомы, которые теперь доступны в .NET 3.5?

// Args class.
public class TickArgs : EventArgs {
    private DateTime TimeNow;
    public DateTime Time {
        set { TimeNow = value; }
        get { return this.TimeNow; }
    }
}

// Producer class that generates events.
public class Metronome {
    public event TickHandler Tick;
    public delegate void TickHandler(Metronome m, TickArgs e);
    public void Start() {
        while (true) {
            System.Threading.Thread.Sleep(3000);
            if (Tick != null) {
                TickArgs t = new TickArgs();
                t.Time = DateTime.Now;
                Tick(this, t);
            }
        }
    }
}

// Consumer class that listens for events.
public class Listener {
    public void Subscribe(Metronome m) {
        m.Tick += new Metronome.TickHandler(HeardIt);
    }
    private void HeardIt(Metronome m, TickArgs e) {
        System.Console.WriteLine("HEARD IT AT {0}",e.Time);
    }
}

// Example.
public class Test {
    static void Main() {
        Metronome m = new Metronome();
        Listener l = new Listener();
        l.Subscribe(m);
        m.Start();
    }
}

Ответы [ 4 ]

1 голос
/ 05 мая 2010

Для начала вы не должны определять свои собственные типы делегатов для событий. Вместо этого используйте System.EventHandler<T> или System.EventHandler.

Кроме того, вы можете использовать автоматически реализованные свойства для вашего класса TickArgs (который, кстати, действительно должен называться TickEventArgs, в соответствии с соглашениями .NET):

public class TickEventArgs : EventArgs
{
    public DateTime Time
    {
        get;
        set;
    }
}

Что касается самих событий, есть некоторые ошибки, о которых вы должны знать в .NET, о которых вы можете прочитать в некоторых статьях Джона Скита о многопоточности:

http://www.yoda.arachsys.com/csharp/events.html

Обратите внимание, что события в .NET 4 работают по-разному, и многие ошибки, существующие в 3.5, были очищены.

1 голос
/ 05 мая 2010
// Args class.
public class TickArgs : EventArgs {
    private DateTime TimeNow;
    // Auto property used
    public DateTime Time { get; set; }
}

// Producer class that generates events.
public class Metronome {
    public event TickHandler Tick;
    public delegate void TickHandler(Metronome m, TickArgs e);
    public void Start() {
        while (true) {
            System.Threading.Thread.Sleep(3000);
            // Thread safety introduced
            TickHandler ticker = Tick;
            if (ticker != null) {
                // Object initialiser added
                TickArgs t = new TickArgs { 
                   Time = DateTime.Now;
                }
                ticker(this, t);
            }
        }
    }
}

// Consumer class that listens for events.
public class Listener {
    public void Subscribe(Metronome m) {
        // Event handler replaced with llambda function
        m.Tick += (mm, e) => System.Console.WriteLine("HEARD IT AT {0}",e.Time)
    }
}

// Example.
public class Test {
    static void Main() {
        Metronome m = new Metronome();
        Listener l = new Listener();
        l.Subscribe(m);
        m.Start();
    }
}

Вы можете улучшить событие Tick следующим образом

  // Producer class that generates events.
    public class Metronome {
        // Add a dummy event handler and ensure that there's no unsafe thread issues 
        public event TickHandler Tick = (m, e) => {};
        public delegate void TickHandler(Metronome m, TickArgs e);
        public void Start() {
            while (true) {
                System.Threading.Thread.Sleep(3000);
                // no need to check for null before calling
                Tick(this, new TickArgs { Time = DateTime.Now; });
            }
        }
    }

У меня нет компиляции, но вы можете улучшить событие Tick, как это, я думаю

  // Producer class that generates events.
    public class Metronome {
        // Add a dummy event handler and ensure that there's no unsafe thread issues 
        public event EventHandler<TickArgs> Tick = (m, e) => {};
        public void Start() {
            while (true) {
                System.Threading.Thread.Sleep(3000);
                // no need to check for null before calling
                Tick(this, new TickArgs { Time = DateTime.Now; });
            }
        }
    }
0 голосов
/ 05 мая 2010

Вот как бы я это сделал. Во-первых, обратите внимание, что я сделал TickArgs sealed и неизменяемым через readonly для переменных-членов. Во-вторых, я удалил делегат TickHandler и заменил на EventHandler<TickArgs>. В-третьих, само событие Tick теперь является частным (переименовано в _Tick) и доступно через свойство. Наконец, для перехвата события в Listener используется лямбда-выражение (т.е. встроенный делегат), а не явный метод.

namespace Events3
{
    using System;

    // Args class.
    public sealed class TickArgs : EventArgs
    {
        private readonly DateTime TimeNow;
        public DateTime Time
        {
            get { return this.TimeNow; }
        }
        public TickArgs(DateTime TimeNow)
        {
            this.TimeNow = TimeNow;
        }
    }

    // Producer class that generates events.
    public sealed class Metronome
    {
        private event EventHandler<TickArgs> _Tick;
        public event EventHandler<TickArgs> Tick
        {
            add { this._Tick += value; }
            remove { this._Tick -= value; }
        }
        public void Start()
        {
            while (true)
            {
                System.Threading.Thread.Sleep(3000);
                EventHandler<TickArgs> tick = this._Tick;
                if (tick != null)
                {
                    tick(this, new TickArgs(DateTime.Now));
                }
            }
        }
    }

    // Consumer class that listens for events.
    public sealed class Listener
    {
        public void Subscribe(Metronome m)
        {
            m.Tick += (sender, e) =>
            {
                System.Console.WriteLine("HEARD IT AT {0}", e.Time);
            };
        }
    }

    // Example.
    public static class Test
    {
        static void Main()
        {
            Metronome m = new Metronome();
            Listener l = new Listener();
            l.Subscribe(m);
            m.Start();
        }
    }
}
0 голосов
/ 05 мая 2010

Для начала вы можете использовать автоматически сгенерированные свойства:

public class TickArgs : EventArgs {
     public DateTime Time {
        set;
        get;
    }
}

Вам также не нужно создавать экземпляр слушающего делегата:

public void Subscribe(Metronome m) {
    m.Tick += HeardIt;
}
...