【问题标题】:c# Argument is 'ref' while parameter is declared as 'value'c#参数是'ref',而参数被声明为'value'
【发布时间】:2011-07-05 19:04:27
【问题描述】:
public virtual IAsyncResult BeginProcessRequest(RequestContext context, AsyncCallback callback, object state)
{
    return this.process.BeginInvoke(**ref context**, callback, state);
}

public virtual RequestContext EndProcessRequest(IAsyncResult result)
{
    RequestContext context = null;
    this.process.EndInvoke(**ref context**, result);
    return context;
}

上述两种方法在我的项目中引起了一些警告。我不确定我是否理解他们。警告是:

参数是'ref',而参数被声明为'value'

并且警告的位置是 Invoke 调用中的第一个参数(上下文)。有没有人认为这有什么问题或对这个问题有什么建议?

那些双星号是警告的原因。我在编辑器上点击了“粗体”,它做到了,所以我就跟着它去了。星号不在我的代码中。

【问题讨论】:

  • 这没什么大不了的,我仍然可以编译,这似乎不是问题,但我真的很讨厌“未知数”:)
  • process的类型是什么?
  • 进程为:delegate void Microsoft.ServiceModel.Web.Process(ref RequestContext context)
  • @J 本杰明:嗯。这听起来像一个非常丑陋的代表签名......
  • 好吧,幸运的是我不能声称这是我自己的创作。 :) 混淆是正确的......我总是在这里告诉团队,“为你的程序员同事编程”......并不总是发生

标签: c# resharper ref performance


【解决方案1】:

ref 与代表一起使用是个坏主意,IMO。 (老实说,我想说这通常是个坏主意。让你的方法做一件事并产生一个结果。)

我认为它根本不会起作用 - 但显然它会起作用,只要您在调用 EndInvoke 时也提供 ref 参数:

using System;

class Program
{
    delegate void Foo(ref int x, string y);

    static void SampleFoo(ref int x, string y)
    {
        Console.WriteLine("Incoming: {0}", x); // 10
        x = y.Length;
    }

    static void Main(string[] args)
    {
        int x = 0;
        int input = 10;
        Foo f = SampleFoo;
        IAsyncResult result = f.BeginInvoke(ref input, "Hello", null, null);
        f.EndInvoke(ref x, result);
        Console.WriteLine("Result: {0}", x); // 5
    }
}

这里的行为可能令人困惑......如果可能的话,我会避免它。

ref 的大多数用法是由于不理解 how parameter passing works in C#... 可能是这种情况吗?你真的需要第一个参数是ref吗?你能把委托的返回值改为新的上下文吗?

【讨论】:

    【解决方案2】:

    BeginInvoke 可能不希望有ref 参数。你说ref context,即传递对该对象的引用(本身就是一个引用)。你能确认BeginInvoke的方法签名吗?

    【讨论】:

    • BeginInvoke 的签名与他所在的方法签名相同:BeginInvoke(RequestContext context, AsyncCallback callback, object state)..
    • @JBenjamin 完全正确,如果方法签名有ref,您只能使用ref
    • 是的,这就是我的观点——ref 做了一些非常具体的事情,除非你调用的方法也声明了ref,否则你不应该使用它。如果这没有意义,建议查看msdn.microsoft.com/en-us/library/14akc2c7(v=vs.71).aspx 这些文档
    【解决方案3】:

    我认为你并不完全理解 ref 的工作原理。

    首先,ref(或out)是方法签名的一部分,所以如果在方法中将参数指定为ref参数,那么你必须使用@987654325 @ 否则你不得使用ref

    次于:

    public virtual IAsyncResult BeginProcessRequest(RequestContext context, AsyncCallback callback, object state)
    {
        return this.process.BeginInvoke(ref context, callback, state);
    }
    

    ref 不会做任何事情,因为您不会在任何地方使用 context 的新值。 ref 类似于out 参数,只是它既是“in”又是“out”。普通参数只能被认为是“in”(我正在编造术语“in”)。

    【讨论】:

    • 在调用BeginInvoke 之后没有context 的新值。当您致电EndInvoke 时,就会出现这种情况。有关示例,请参见我的答案。正是这种怪异使得将ref 用于异步委托是个坏主意……
    • @Jon 我意识到,我想也许我没有说清楚。我的意思是,如果BeginInvoke 被定义为采用ref 参数,那么预计ref 参数会被修改,否则就不需要将其设为ref
    • 是的,并且 ref 参数 可能会被修改 - 并且根据 OP 的 EndProcessRequest,在 EndInvoke 期间使用另一个 ref 参数读出新值方法。所以 ref 确实 做了一些事情 - 它允许在 EndInvoke 调用中获取新值。
    猜你喜欢
    • 2010-10-20
    • 2015-10-02
    • 2022-09-30
    • 1970-01-01
    • 2019-01-15
    • 2021-11-30
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多