views:

89

answers:

6

Say i have the following two classes:

public class User
    {
        public int ID { get; }

        public string Name { get; set; }

        public void ChangeName(string newName)
        {
            Name = newName;
        }


    }

    public class Mail
    {
        public void SendUserInfoChangeEmail()
        {
            throw new NotImplementedException();
        }
    }

and what i want to do is: when the someone edit user object name using the method ChangeName the SendUserInfoChangeEmail get called automatically.

And i know that i can use events to handle this issue, but what i want is to make a 3rd static class to build in it this events, and will say in the class: attach ChangeName to SendUserInfoChangeEmail

How can i do this?

NOTE:
I don't want to put any event handling or delegates in both user and email classes i want everything to manage through this third new static class.

+2  A: 

You can create an event on the user class and subscribe to it in a 3rd class.

You may want to look at the INotifyPropertyChanged interface to see how things like this are done by others.

http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(VS.96).aspx

Sruly
A: 

Your user class needs to have an event that is fired with the username changes. Whichever object keeps track of the users will need to have a method that is subscribed to username change event and can create a new Mail object and send the necessary email.

To create the event in the user class, do this:

public class User {
    public event EventHandler UserNameChanged;

    private string m_Name;
    public string Name {
        get { return m_Name; }
        set {
            if(m_Name != value) {
                m_Name = value;
                // assuming single-threaded application
                if(UserNameChanged != null)
                    UserNameChanged(this, EventArgs.Empty);
            }
        }
    }

    // everything else is the same...
}

In the managing code, you will have a method that handles the event:

private void Handle_UserNameChanged(object sender, EventArgs e) {
    User user = (User)sender;
    // create the mail object and send it        
}

I don't think your Mail class as it stands now will work. If Mail is meant to represent a mail message, then it should provide all the methods and properties necessary to set up a mail message and to send it. But if all you need to do is use the .NET framework's mail system to send the email, then Mail could be a static class with methods that send various types of predefined email (not the best design, but workable as a start), including a method SendUserInfoChangeEmail(). That can be called by your event handler.

siride
A: 

In terms of design patterns, take a look at the Observer Pattern

Victor Hurdugaci
A: 
  1. Why would you want a ChangeUser method in addition to the Name property which serves exactly the same purpose just much cleaner?
  2. What does SendUserInfoChangeEmail mean? What is its purpose? Why is it in the Mail class? Wouldn't it be better to have that in the User class or something similar?
  3. Why a static third class?

Anyways, I would change the User class to something like this:

public class User : INotifyPropertyChanged
{
    public int ID { get; }

    private string name;
    public string Name
    {
        get { return name; }
        set 
        {
            if(value != name)
            {
                name = value; 
                NotifyPropertyChanged("Name");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

Then in wherever you feel like it, your static class or whatever, subscribe to that event and send the email when the name has changed.

Svish
Make sure to implement INotifyPropertyChanged.
siride
infact i want to make something like that http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.aspx but more simple, i want to create an example which complete this http://martinfowler.com/eaaDev/EventAggregator.html
Amr ElGarhy
@siride: Thanks, forgot to add that
Svish
@Amr: If you want something simpler than an Event Aggregator, I'd do something different, like for example what I suggested. Or something completely different.
Svish
+1  A: 

I think what you are talking about is sometimes called an event proxy class. It is a class that serves as an intermediary when you don't want to have a hard dependency between two classes.

In general, I try to avoid using it whenever I can get a reference to the firing object, but there are some legitimate scenarios where the consumer of an event may not be aware of all of the instances that may fire it. For example, where I've used this before is to provide a global data refresh event when there are multiple views of the data and the data is not in a single domain object that can be directly referenced.

public class User
{
    public int ID { get; }

    public string Name { get; set; }

    public void ChangeName(string newName)
    {
        Name = newName;
        UserEventProxy.FireUserNameChanged(this);
    }
}

public class UserEventArgs : EventArgs
{
    public User User{get; set;}
}

/// <summary>
/// 
/// </summary>
public static class UserEventProxy
{
    /// <summary>
    /// Indicates that the associated user's name has changed.
    /// </summary>
    public static event EventHandler<UserEventArgs> UserNameChanged;

    /// <summary>
    /// Fires the UserNameChanged event.
    /// </summary>
    /// <param name="user">The user reporting the name change.</param>
    public static void FireUserNameChanged(User user)
    {
        EventHandler<UserEventArgs> handler = UserNameChanged;
        if (handler != null)
        {
            UserEventArgs args = new UserEventArgs()
            {
                User = user
            };

            //Fire the event.
            UserNameChanged(user, args);
        }
    }
}


public class Mail
{
    public Mail()
    {
        UserEventProxy.UserNameChanged += new EventHandler<UserEventArgs>(UserEventProxy_UserNameChanged);
    }

    private void UserEventProxy_UserNameChanged(object sender, UserEventArgs e)
    {
        User user = e.User;

        //
        //Presumably do something with the User instance or pass it to 
        //the SendUserInfoChangedEmail method. to do something there.
        //

        SendUserInfoChangeEmail();
    }


    public void SendUserInfoChangeEmail()
    {
        throw new NotImplementedException();
    }
}
Rob Cooke
+1  A: 

The pattern that you want seems to be the Mediator. This simple example gives you the idea:

public class User {
  public event EventHandler NameChanged = delegate { };
  public int ID { get; }
  public string Name { get; private set; }
  public void ChangeName(string newName) {
    if (newName != Name) {
      NameChanged(this, EventArgs.Empty);
    }
    Name = newName;
  }
}

public class UserMediator {
  User _user;
  EventHandler _eh;
  public UserMediator(User user, Action onNameChanged) {
    _user = user;
    _eh = (src, args) => onNameChanged();
    _user.NameChanged += _eh;
  }
  public void Detach() {
    _user.NameChanged -= _eh;
  }
}

Somewhere else:

var user = new User();
var mail = new Mail();
new UserMediator(user, mail.SendUserInfoChangeEmail);
Jordão