CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10
  1. #1
    Join Date
    Apr 2011
    Posts
    58

    Which timer fired?

    OK, I asked this question a couple of weeks ago, and I was given an answer that suited me at the time, but my requirements have changed a bit. I would like to know when a time.elapsed fires, which timer it was that fired. Previously it was good enough to just look through my timer dictionary for a timer with the same parameters as the one sent along with the event. But I have seen that I may have multiple timers with the same parameters. So I decided to roll my own timer class which inherits from System.Timers.Timer, and adds a couple of items. (In case you are wondering, I am writing a program that calculates ISS flyovers and generates notifications for the flyovers)

    Code:
    class FlyoverNotification : System.Timers.Timer
    {
        public System.DateTime targetNotificationTime = new DateTime();
        public string key = "";
    }
    Here's how I implement it
    Code:
    if (!_flyoverNotificationList.ContainsKey(k))
    {
        FlyoverNotification n = new FlyoverNotification();
        n.Elapsed += new System.Timers.ElapsedEventHandler(UpcomingFlyover);
        n.Interval = interval;
        n.Enabled = true;
        n.AutoReset = false;
        n.targetNotificationTime = isc.flyoverStart - ts;
        n.key = k;
        _flyoverNotificationList.Add(k, n);
    }
    And here's the event handler, which doesn't work
    Code:
    public void UpcomingFlyover(Object sender, System.Timers.ElapsedEventArgs e)
    {
      var firedtimer = (from tmpflyover in _flyoverNotificationList
                            where tmpflyover.Value.notificationTimer.Equals(sender)
                            select tmpflyover).FirstOrDefault();
      // do other stuff
    }
    The problem is, when the event handler is fired, if I put a debugging breakpoint on the var firedtimer = line, I do see that Object sender does contain the correct FlyoverNotification parameters, such as sender.key. However, I cannot put sender.key in the LINQ where clause. Do I need to somehow cast the sender as a FlyoverNotification object? Or is my approach all wrong?

  2. #2
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Which timer fired?

    The sender will always be the timer that fired the event. You can cast it back to it's original type:
    FlyoverNotification theTimer = (FlyoverNotification)sender;
    or, if there is a chance that the actual type might be something other than FlyoverNotification:
    FlyoverNotification theTimer = sender as FlyoverNotification;
    if (theTimer != null)
    { // ...

    No need to over-complicate things. I mean, the LINQ query is really unnecessary. If you need to compare against a specific timer for some reason, you can use object.ReferenceEquals();

    P.S. About type-casting in C#: http://msdn.microsoft.com/en-us/library/cc488006.aspx
    Last edited by TheGreatCthulhu; July 6th, 2011 at 02:38 PM.

  3. #3
    Join Date
    Apr 2011
    Posts
    58

    Re: Which timer fired?

    It worked perfectly. Thanks. I got rid of the LINQ query too. My only question is why does this work? If the elapsed eventhandler only passes the actual timer, then how does casting it back to my inherited class reconnect that timer with the other properties in my inherited class instance? I did read over the code example in the link you provided, but it doesn't give any insight to this question.

  4. #4
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Which timer fired?

    Quote Originally Posted by MrGibbage View Post
    It worked perfectly. Thanks. I got rid of the LINQ query too. My only question is why does this work? If the elapsed eventhandler only passes the actual timer, then how does casting it back to my inherited class reconnect that timer with the other properties in my inherited class instance? I did read over the code example in the link you provided, but it doesn't give any insight to this question.
    Read up on Event and how to fire events. You'll notice that the sender parameter [usually] gets set to the object that fires the event.

  5. #5
    Join Date
    Apr 2011
    Posts
    58

    Re: Which timer fired?

    I think my question may be specific to Timer-fired events, and more specifically to classes that inherit from System.Timers.Timer. When an instance of an inherited class fires the Elapsed event, the event handler receives an Object of the base class, not the inherited class. My question is, how can casting a Timer back to the inherited class restore the other properties within that inherited class?

    Maybe this question is generic to all inherited classes. If I have an instance of a base class for which I have created an inherited class, what happens when you cast that base class object to an inherited class object? What sets the values of all the other parameters and objects within that inherited class? The constructor for the inherited class?

  6. #6
    Join Date
    May 2011
    Location
    Washington State
    Posts
    220

    Re: Which timer fired?

    Quote Originally Posted by MrGibbage View Post
    When an instance of an inherited class fires the Elapsed event, the event handler receives an Object of the base class, not the inherited class...
    What makes you think the object being sent in an event is of the object's base class?

  7. #7
    Join Date
    Apr 2011
    Posts
    58

    Re: Which timer fired?

    I thought that it was the base class because I had to cast it back to my inherited class in order to access the other properties and objects of the inherited class. Is that not the right way to think about it? Is it the same as casting say, and int to a double?

  8. #8
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Which timer fired?

    Quote Originally Posted by MrGibbage View Post
    I thought that it was the base class because I had to cast it back to my inherited class in order to access the other properties and objects of the inherited class. Is that not the right way to think about it? Is it the same as casting say, and int to a double?
    As I mentioned earlier, it's dependent on what the sender value was set to when the event was fired.

    I suggested to read up on Events so that you would see that the developer is responsible for setting the sender when firing the event. It appears that in the timer event implementation, the sender has been set to the inherited class.

  9. #9
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Which timer fired?

    The inheritance relationship is an is-a relationship, so your FlyoverNotification is a Timer, in the same sense a dog is a mammal, or a cow is a mammal, or a mammal is an animal.

    So, your subclass specific details are never lost, it's just that your object is treated in a more abstract way, through a more abstract type. This is inheritance-based polymorphism: you can treat a family of related objects the same way.

    For example:
    Code:
    // Animal defines a common interface - what each animal should be able to do.
    // Specialized classes may or may not add new functionality, but they will all be able to Move.
    public abstract class Animal
    {
        public abstract void Move();
    }
    
    public class Dog : Animal
    {
        // A dogs moves one way...
        public override void Move()
        {
            Console.WriteLine("The dog is running!");
        }
    }
    
    public class Bird : Animal
    {
        // A bird moves another
        public override void Move()
        {
            Console.WriteLine("The bird is flying!");
        }
    }
    
    // somewhere in code...
    List<Animal> animals = new List<Animal>();
    animals.Add(new Dog());
    animals.Add(new Bird());
    
    foreach (Animal a in animals)
    {
        a.Move();
    }
    Output:
    The dog is running!
    The bird is flying!


    See? Nothing is ever lost or reconstructed, it's all there, all the time.
    Casting just let's you treat your object in a more specific way.
    For example, let's say that Dog was defined like this:
    Code:
    public class Dog : Animal
    {
        // A dogs moves one way...
        public override void Move()
        {
            Console.WriteLine("The dog is running!");
        }
    
        // Aditional, Dog-specific functionality
        public void Bark()
        {
            Console.WriteLine("Woof!");
        }
    }
    You can't call the Bark() method via an Animal variable. Not every animal can bark! But, if you know that the actual type of the object is Dog, then you can cast it to that type:
    Code:
    Animal a = new Dog();
    
    // a.Bark() will not compile.
    
    Dog theDog = (Dog)a;
    theDog.Bark();
    
    // Outputs: Woof!
    Now, your derived timer inherits the event raising mechanism from the Timer class. There, when the event is raised, the sender object is set to point to the timer instance itself (with sender = this). In your case, the actual type of the timer instance is FlyoverNotification.

    The type of sender is object: this is the base type for all other types in C# - every class implicitly inherits from object, so every class also has all the methods defined in object.
    This is why FlyoverNotification can be treated as object. This is also why the class raising the event can assign an instance of any type as the sender.
    When you cast it back to FlyoverNotification, you're just telling the C# language: OK, I know what this actually is, and I want to treat it as such.
    Last edited by TheGreatCthulhu; July 7th, 2011 at 02:49 PM.

  10. #10
    Join Date
    Apr 2011
    Posts
    58

    Re: Which timer fired?

    Thank you so much for the detailed and comprehensive response! If you aren't teaching this stuff as a profession, I think you should consider it!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured