Особенности делегирования - PullRequest
3 голосов
/ 04 февраля 2011

У меня проблема с делегатом в классе над проектом, над которым я работаю. Класс - это GUI-компонент, который принимает и метку, и значение. Идея состоит в том, что пользователь может указать метку, а затем связать значение из любого места (более конкретно, метод ToString этого значения), чтобы каждый раз, когда это значение обновлялось, компонент GUI также был. Вот основные принципы его настройки:

public delegate string GUIValue();

public class GUIComponent
{
    GUIValue value = null;    // The value linked in
    string label = "";        // The label for the value
    string text = "";         // The label and value appended together

    public GUIComponent(string Text, GUIValue Value)
    {
        this.text = Text;
        this.value += Value;
    }

    public void Update()
    {
        this.text = this.label + this.value();
    }
}

А потом я называю это так

GUIComponent component = new GUIComponent("Label: ",
                                new GUIValue(this.attribute.ToString));

Код компилируется правильно, компонент отображается и отображает начальное значение для данного атрибута, однако он не обновляется при изменении значения атрибута.

Мой вопрос заключается в том, правильно ли я вообще настроил это, и если да, то почему это не сработало. Сначала я думал, что он принимает только первое значение, возвращаемое методом ToString, поскольку он не принимает никаких аргументов, но может ли кто-нибудь это проверить?

Ответы [ 4 ]

1 голос
/ 04 февраля 2011

Почему бы просто не использовать ToString?

public class GUIComponent
{
    object value = null;    // The value linked in
    string label = "";        // The label for the value
    string text = "";         // The label and value appended together

    public GUIComponent(string Text, object Value)
    {
        this.text = Text;
        this.value = Value;
    }

    public void Update()
    {
        this.text = this.label + this.value.ToString();
    }
}
1 голос
/ 04 февраля 2011

Этот код:

new GUIValue(this.attribute.ToString)

не будет вызывать метод при каждом изменении атрибута. Вы должны будете сохранить делегата и вызывать его каждый раз, когда кто-то меняет «атрибут». Что-то вроде:

private event GUIValue attributeChanged = () => this.attribute.ToString();

private String attribute;

// This is a property that sets the value of attribute
public String Attribute { get { return attribute; } set { attribute = value; attributeChanged(); } }

// Now you can initialize the component using:
// GUIComponent component = new GUIComponent("Label: ", this.attributeChanged);
1 голос
/ 04 февраля 2011

У вас есть половина этого.Я думаю, что происходит то, что, хотя вы можете изначально получить значение, ваш GuiComponent не сообщается никаким классом, у которого фактически есть метод, данный как делегат GUIValue, что значение действительно изменилось и повторно его получить.Обычный метод сообщения другим объектам о том, что что-то произошло, - это событие, на которое другие объекты «подписываются» путем передачи делегатов, которые будут запускаться при возникновении события.

Вот как я структурировал бы ваш код:

public interface IHaveAValueYouNeed 
{
    string ValueGetter();
    event EventArgs ValueChanged;
}

public class GUIComponent
{
    public delegate string ValueGetter();

    ValueGetter getter;    // The value linked in
    string label = "";        // The label for the value
    string text = "";         // The label and value appended together

    public GUIComponent(string Text, IHaveAValueYouNeed getter)
    {
        this.text = Text;
        this.getter += getter.ValueGetter;
        getter.ValueChanged += ValueUpdatedHandler;
    }

    public void Update()
    {
        this.text = this.label + this.value();
    }

    public void ValueUpdatedHandler(object sender, EventArgs e)
    {
        Update();
    }
}

Теперь, когда вы передаете реализацию интерфейса компоненту, компонент будет обмениваться делегатами с экземпляром, получая ссылку на свой ValueGetter и подписываясь на его событие.Реализации IHaveAValueYouNeed должны затем вызывать событие, когда значение изменяется (либо напрямую, либо потому, что изменилось что-то, что могло бы изменить вычисленное значение, произведенное получателем).Таким образом, объект, управляющий значением, может сообщить заинтересованным в этом значении людям, что оно изменилось.

1 голос
/ 04 февраля 2011

Делегат должен быть вызван.
У вас есть value метод ссылки this.attribute.ToString.

Это означает, что когда вы вызовете this.value(), будет вызвана эта функция.

Когда вы меняете значение this.attribute, вы, вероятно, делаете это, ссылаясь на другой объект, содержащий другое значение.
Итак, я думаю, что вы испытываете то, что каждый раз, когда вы звоните update(), появляется старое значение. Это потому, что старый объект не уничтожен сборщиком мусора, потому что вы держите ссылку на него через делегат.

Когда вы изменили значение атрибута, делегат GUI по-прежнему содержит метод старого объекта, а не новый.

...