Как прикрепить событие к методу в общем классе? - PullRequest
1 голос
/ 08 августа 2010

Скажите, у меня есть следующие два класса:

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-й статический класс, чтобы встроить в него эти события, и скажу в классе: присоединить ChangeName к SendUserInfoChangeEmail

Как я могу это сделать?

Примечание:
Я не хочу ставить события обработка или делегаты в обоих пользователях и по электронной почте классы, я хочу все управлять через этот третий новый статический класс.

Ответы [ 6 ]

2 голосов
/ 08 августа 2010

Вы можете создать событие в классе пользователя и подписаться на него в третьем классе.

Возможно, вы захотите взглянуть на интерфейс INotifyPropertyChanged, чтобы увидеть, как такие вещи делают другие.

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

1 голос
/ 09 августа 2010

Шаблон, который вам нужен, выглядит как 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);
1 голос
/ 08 августа 2010

Я думаю, что то, о чем вы говорите, иногда называют прокси-классом события.Это класс, который служит посредником, когда вы не хотите иметь жесткую зависимость между двумя классами.

В общем, я стараюсь избегать его использования всякий раз, когда могу получить ссылку на объект обжига,но есть некоторые законные сценарии, когда потребитель события может не знать обо всех случаях, которые могут его запустить.Например, где я использовал это раньше - это предоставление глобального события обновления данных, когда существует несколько представлений данных, и данные не находятся в одном объекте домена, на который можно напрямую ссылаться.

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();
    }
}
0 голосов
/ 08 августа 2010
  1. Зачем вам нужен метод ChangeUser в дополнение к свойству Name, который служит точно такой же цели, только намного чище?
  2. Что означает SendUserInfoChangeEmail? Какова его цель? Почему это в классе Mail? Разве не было бы лучше иметь это в классе User или что-то подобное?
  3. Почему статический третий класс?

В любом случае, я бы изменил класс 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));
    }
}

Тогда, где бы вам ни хотелось, ваш статический класс или что-то еще, подпишитесь на это событие и отправьте электронное письмо, когда имя изменилось.

0 голосов
/ 08 августа 2010

Что касается шаблонов проектирования, взгляните на Шаблон наблюдателя

0 голосов
/ 08 августа 2010

Ваш класс пользователя должен иметь событие, которое запускается с изменениями имени пользователя.Какой бы объект не отслеживал пользователей, он должен иметь метод, который подписан на событие изменения имени пользователя и может создавать новый объект 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 Framework для отправки электронной почты, то Mail может быть статическим классом с методами, которые отправляют различные типы предопределенных электронных писем (не лучший дизайн, но работоспособный в начале), включаяметод SendUserInfoChangeEmail ().Это может вызвать ваш обработчик событий.

...