Как правильно каскадно сохранить однонаправленное двустороннее отношение к первичному ключу в Hibernate 3.6

ПРИМЕЧАНИЕ. Если у вас есть доступ к C # 5.0 Unleashed , прочитайте «Ограничения на обычное использование делегатов» в главе 18 под названием «События», чтобы лучше понять различия между ними.


Это всегда помогает мне составить простой, конкретный пример. Итак, вот для сообщества. Сначала я покажу, как вы можете использовать только делегатов, чтобы делать то, что делают для нас события. Затем я покажу, как одно и то же решение будет работать с экземпляром EventHandler. И затем я объясню, почему мы НЕ хотим делать то, что я объясняю в первом примере.

Пример 1: Использование public delegate

Предположим, у меня есть приложение WinForms с одним раскрывающимся списком коробка. Выпадающий объект привязан к List. Где Person имеет свойства Id, Name, NickName, HairColor. В основной форме используется пользовательский элемент управления, который показывает свойства этого человека. Когда кто-то выбирает человека в раскрывающемся списке меток в обновлении пользовательского управления, чтобы показать свойства выбранного человека.

enter image description here [/g5]

Вот как это работает. У нас есть три файла, которые помогают нам объединить это:

  • Mediator.cs - статический класс содержит делегатов
  • Form1.cs - основная форма
  • DetailView.cs - пользовательский элемент управления показывает все подробности

Вот соответствующий код для каждого из классов:

class Mediator
{
    public delegate void PersonChangedDelegate(Person p); //delegate type definition
    public static PersonChangedDelegate PersonChangedDel; //delegate instance. Detail view will "subscribe" to this.
    public static void OnPersonChanged(Person p) //Form1 will call this when the drop-down changes.
    {
        if (PersonChangedDel != null)
        {
            PersonChangedDel(p);
        }
    }
}

Вот наш пользовательский элемент управления:

public partial class DetailView : UserControl
{
    public DetailView()
    {
        InitializeComponent();
        Mediator.PersonChangedDel += DetailView_PersonChanged;
    }

    void DetailView_PersonChanged(Person p)
    {
        BindData(p);
    }

    public void BindData(Person p)
    {
        lblPersonHairColor.Text = p.HairColor;
        lblPersonId.Text = p.IdPerson.ToString();
        lblPersonName.Text = p.Name;
        lblPersonNickName.Text = p.NickName;

    }
}

Наконец, у нас есть следующий код в нашем Form1.cs. Здесь мы вызываем OnPersonChanged, который вызывает любой код, подписанный на делегат.

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
}

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

НО, НО, НО, мы не хотим делать то, что я только что описал выше. Потому что публичные поля плохие по многим причинам. Итак, каковы наши варианты? Как описывает Джон Скит, вот наши варианты:

  1. Публичная переменная делегата (это то, что мы только что сделали выше, не делайте этого, я просто сказал вам выше, почему это плохо)
  2. Поместите делегат в свойство с get / set (проблема заключается в том, что подписчики могут переопределять друг друга, поэтому мы можем подписывать кучу методов делегату, а затем мы могли бы случайно сказать PersonChangedDel = null, вытирая Другие проблемы, которые остаются здесь, это то, что, поскольку пользователи имеют доступ к делегату, они могут вызывать цели в списке вызовов - мы не хотим, чтобы внешние пользователи имели доступ к тому, когда нужно поднимать наши события .
  3. Переменная делегата с методами AddXXXHandler и RemoveXXXHandler

Эта третья опция - это то, что нам дает событие. Когда мы объявляем EventHandler, он дает нам доступ к делегат - не публично, а не как свойство, но в качестве этой вещи мы называем событие, которое просто добавляет / удаляет аксессоры.

Давайте посмотрим то, что похоже на ту же программу, но теперь использует событие вместо публичного делегата (я также изменил наш посредник на одноэлементный):

Пример 2: с EventHandler вместо публичного делегата

Посредник:

class Mediator
{

    private static readonly Mediator _Instance = new Mediator();

    private Mediator() { }

    public static Mediator GetInstance()
    {
        return _Instance;
    }

    public event EventHandler PersonChanged; //this is just a property we expose to add items to the delegate.

    public void OnPersonChanged(object sender, Person p)
    {
        var personChangedDelegate = PersonChanged as EventHandler;
        if (personChangedDelegate != null)
        {
            personChangedDelegate(sender, new PersonChangedEventArgs() { Person = p });
        }
    }
}

Обратите внимание, что если вы F12 в EventHandler, он покажет вам, что это определение является только делегатом с общим назначением с дополнительным объектом «отправитель»:

public delegate void EventHandler(object sender, TEventArgs e);

Пользовательский контроль:

public partial class DetailView : UserControl
{
    public DetailView()
    {
        InitializeComponent();
        Mediator.GetInstance().PersonChanged += DetailView_PersonChanged;
    }

    void DetailView_PersonChanged(object sender, PersonChangedEventArgs e)
    {
        BindData(e.Person);
    }

    public void BindData(Person p)
    {
        lblPersonHairColor.Text = p.HairColor;
        lblPersonId.Text = p.IdPerson.ToString();
        lblPersonName.Text = p.Name;
        lblPersonNickName.Text = p.NickName;

    }
}

Наконец, вот код Form1.cs:

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
        Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
}

Поскольку EventHandler хочет и EventArgs в качестве параметра, я создал этот класс только с одним свойством:

class PersonChangedEventArgs
{
    public Person Person { get; set; }
}

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

37
задан Pascal Thivent 26 October 2010 в 23:49
поделиться