Считается ли добавление в группу методов использованием переменной? - PullRequest
6 голосов
/ 15 февраля 2011

У меня есть следующий пример кода, взятый из кода Form:

    protected void SomeMethod()
    {
        SomeOtherMethod(this.OnPaint);
    }

    private void SomeOtherMethod(Action<PaintEventArgs> onPaint)
    {
        onPaint += MyPaint;
    }

    protected void MyPaint(PaintEventArgs e)
    {
        // paint some stuff
    }

Второй метод (SomeOtherMethod) вызывает резкие жалобы на меня.Это говорит о onPaint, что «Присвоенное значение не используется ни в каком пути выполнения» .

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

Но обычно, когда resharper говорит мне что-то вроде этого, это потому, что я не понимаю какую-то часть C #.Например, когда параметр выходит из области видимости, элемент, который я добавил в список, удаляется (или что-то в этом роде).

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

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

Ответы [ 5 ]

8 голосов
/ 15 февраля 2011

Предупреждение верно.Рассмотрим следующее:

int X;
int Y;
void SomeMethod()
{         
    SomeOtherMethod(this.X);
}      
void SomeOtherMethod(int x)
{
    x += this.Y;
}

Здесь код модифицирует формальный параметр x, а затем никогда не использует измененный x.Это не меняет "this.X"

Вы сделали то же самое с делегатом.Вы изменяете формальный параметр и затем никогда не используете результат;исходный «OnPaint» не изменился, так же как «X» не изменился в моем примере.

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

5 голосов
/ 15 февраля 2011

Делегаты неизменны. Вы не можете их изменить. В этом отношении они немного похожи на струны. Представьте, что ваш метод был:

private void SomeOtherMethod(string x)
{
    x += "hello";
}

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

Либо вам нужно передать переменную по ссылке , либо , вам нужно изменить весь ваш дизайн.

См. Мою статью о делегатах и ​​событиях , чтобы узнать больше о том, как работает объединение делегатов.

5 голосов
/ 15 февраля 2011

Это работает вообще?Я не ожидаю, что MyPaint когда-либо вызывается.Это было бы подсказкой.

Мне кажется, что onPaint += MyPaint; не будет иметь никакого эффекта вне этого метода.onPaint - это параметр (локальная переменная), и изменения теряются при выходе из метода.И именно поэтому вы получаете предупреждение.

Чтобы понять почему, вам понадобится что-то вроде ref параметра, но вы не можете вызвать это с событием (this.Onpaint):

// not applicable
private void SomeOtherMethod(ref Action<PaintEventArgs> onPaint)
{
   onPaint += MyPaint;
}
5 голосов
/ 15 февраля 2011

Делегаты являются неизменными, поэтому объединение создает копию. Когда вы звоните:

private void SomeOtherMethod(Action<PaintEventArgs> onPaint)

Вы фактически создаете измененную копию оригинала Action<PaintEventArgs>.

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

Лично я рассмотрел бы создание интерфейса, который выставляет событие OnPaint, и передачу интерфейса в этот метод. Затем вы можете подписаться на событие. Это будет иметь тот же эффект, которого вы пытаетесь достичь, но будет гораздо яснее.

В этом случае я бы просто попросил ваш другой класс подписаться на Событие Paint непосредственно в Control.

2 голосов
/ 15 февраля 2011

После некоторых экспериментов, я думаю, причина в том, что когда вы делаете += для Action, вы изменяете не начальное значение, а локальную переменную. Например:

void Main()
{
    Action<int> doSomething = OnClick;
    doSomething += i=> Console.WriteLine("test");
    OnClick(1);
}

private void OnClick(int i)
{
    Console.WriteLine("clicked");
}

... просто выдает "нажал".

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

Редактировать

Поргес отмечает, что, поскольку OnClick является методом (а не делегатом), этот пример не совсем точен. Вот лучше:

Action<int> doSomething = i => Console.WriteLine("test");
var doSomething2 = doSomething; 
doSomething2 += i => Console.WriteLine("test2");
doSomething(1);

Выход: test

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...