如何将事件附加到公共类中的方法?

时间:2010-08-08 15:00:16

标签: c# design-patterns events event-handling

说我有以下两个类:

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();
        }
    }

我想要做的是:当有人使用方法ChangeName编辑用户对象名称时,SendUserInfoChangeEmail会自动调用。

我知道我可以使用事件来处理这个问题,但我想要的是制作第3个静态类来构建这个事件,并在课堂上说:attach ChangeName to {{ 1}}

我该怎么做?

注意:
我不想发生任何事件    处理或代表两个用户    和电子邮件课我想要一切    管理这第三个新的    静态类。

6 个答案:

答案 0 :(得分:2)

您可以在用户类上创建一个事件,并在第三类中订阅它。

您可能需要查看INotifyPropertyChanged界面,以了解其他人如何完成此类操作。

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

答案 1 :(得分:1)

我认为你所谈论的有时被称为事件代理类。当您不希望在两个类之间存在硬依赖时,它是一个充当中介的类。

一般情况下,每当我可以获得对触发对象的引用时,我都会尽量避免使用它,但是有一些合法的场景,其中事件的使用者可能不知道可能触发它的所有实例。例如,我之前使用过的是当有多个数据视图并且数据不在可以直接引用的单个域对象中时提供全局数据刷新事件。

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();
    }
}

答案 2 :(得分:1)

您想要的模式似乎是Mediator。这个简单的例子为您提供了这个想法:

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;
  }
}

其他地方:

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

答案 3 :(得分:0)

您的用户类需要使用用户名更改触发事件。无论哪个对象跟踪用户,都需要有一个订阅用户名更改事件的方法,并且可以创建一个新的Mail对象并发送必要的电子邮件。

要在用户类中创建事件,请执行以下操作:

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...
}

在管理代码中,您将拥有一个处理事件的方法:

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

我认为你现在的Mail类不会起作用。如果Mail表示邮件消息,则它应提供设置邮件和发送邮件所需的所有方法和属性。但是,如果您只需要使用.NET框架的邮件系统发送电子邮件,那么Mail可以是一个静态类,其方法可以发送各种类型的预定义电子邮件(不是最好的设计,但可以作为开始),包括方法SendUserInfoChangeEmail()。这可以由您的事件处理程序调用。

答案 4 :(得分:0)

在设计模式方面,请查看Observer Pattern

答案 5 :(得分:0)

  1. 除了ChangeUser属性之外,为什么还需要一个Name方法才能提供更清晰的用途?
  2. SendUserInfoChangeEmail是什么意思?它的目的是什么?为什么它在Mail类中?在User类或类似的东西中提供它不是更好吗?
  3. 为什么要静态第三类?
  4. 无论如何,我会将User类改为这样的类:

    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));
        }
    }
    

    然后,无论你想要什么,你的静态类或其他什么,订阅该事件并在名称发生变化时发送电子邮件。