我从Form
的代码中获取了以下代码示例:
protected void SomeMethod()
{
SomeOtherMethod(this.OnPaint);
}
private void SomeOtherMethod(Action<PaintEventArgs> onPaint)
{
onPaint += MyPaint;
}
protected void MyPaint(PaintEventArgs e)
{
// paint some stuff
}
第二种方法(SomeOtherMethod
)有一个resharper抱怨我。它说onPaint
“分配的值未在任何执行路径中使用”。
在我看来它是被使用的,因为我在绘制完成时调用的方法列表中添加了一个方法。
但通常当resharper告诉我这样的事情是因为我不理解C#的某些部分。就像当参数超出范围时,我添加到列表中的项目将被删除(或类似的东西)。
我想我会问这里是否有人知道resharper试图告诉我什么。
(旁注:我通常只是重写OnPaint。但是我试图让OnPaint在另一个类中调用一个方法。我不想公开公开该方法,所以我想我会传入OnPaint组并添加它。)
答案 0 :(得分:8)
警告是正确的。请考虑以下事项:
int X;
int Y;
void SomeMethod()
{
SomeOtherMethod(this.X);
}
void SomeOtherMethod(int x)
{
x += this.Y;
}
这里代码修改形式参数x,然后从不使用修改过的x。这不会修改“this.X”
你和代表做了同样的事情。您修改形式参数,然后从不使用结果;原始的“OnPaint”没有变化,就像我的例子中“X”没有变化一样。
请记住,仅仅因为委托是引用类型并不意味着当您传递实例时,您正在传递对变量的引用。您正在传递对实例的引用,而不是对该实例的存储位置的引用。
答案 1 :(得分:5)
它有用吗?我不指望MyPaint会被调用。那将是一个线索。
在我看来,onPaint += MyPaint;
在此方法之外没有任何影响。 onPaint
是一个参数(局部变量),当方法退出时,更改将丢失。这就是你得到警告的原因。
要了解原因,您需要类似ref
参数的内容,但不能使用事件(this.Onpaint)调用它:
// not applicable
private void SomeOtherMethod(ref Action<PaintEventArgs> onPaint)
{
onPaint += MyPaint;
}
答案 2 :(得分:5)
委托是不可变的,因此组合创建副本。当你打电话:
private void SomeOtherMethod(Action<PaintEventArgs> onPaint)
您实际上是在创建原始Action<PaintEventArgs>
的修改过的副本。
话虽这么说,我个人会避免尝试这种方式,除非有一个非常令人信服的理由这样做。
就个人而言,我会考虑创建一个公开OnPaint
事件的接口,并将接口传递给此方法。然后,您可以订阅该活动。这会产生与你想要达到的效果相同的效果,但要更清楚。
在这种情况下,我会让你的另一个类直接订阅Control上的Paint event。
答案 3 :(得分:5)
代表是不可变的。你无法改变它们。在这方面他们有点像弦乐。想象一下你的方法是:
private void SomeOtherMethod(string x)
{
x += "hello";
}
同样,这将是一个毫无意义的方法。原始字符串不会改变 - 您只是更改了局部变量(参数)的值以引用不同的字符串。在你的委托案件中也会发生同样的事情。
要么你需要通过引用或传递变量,你需要改变整个设计。
有关委托合并的工作原理,请参阅我在delegates and events上的文章。
答案 4 :(得分:2)
在做了一些实验之后,我认为原因是当你在+=
上进行Action
时,你不是在修改初始值,而是修改局部变量本身。例如:
void Main()
{
Action<int> doSomething = OnClick;
doSomething += i=> Console.WriteLine("test");
OnClick(1);
}
private void OnClick(int i)
{
Console.WriteLine("clicked");
}
...只是产生“点击”。
因此,您的示例中的MyPaint方法未被修改,只有onPaint变量。由于您在+=
之后没有对该变量执行任何操作,因此首先执行+=
毫无意义。
修改强>
Porges指出,由于OnClick是一种方法(不是委托),因此这个例子不太准确。这是一个更好的:
Action<int> doSomething = i => Console.WriteLine("test");
var doSomething2 = doSomething;
doSomething2 += i => Console.WriteLine("test2");
doSomething(1);
输出:test