C#隐式更新传递给方法的参数,不使用返回类型,也不使用out或ref

C#隐式更新传递给方法的参数,不使用返回类型,也不使用out或ref,c#,C#,这对我来说太奇怪了,显然开发人员应该使用关键词out,但我不敢相信这居然有效: public BusinessResponse<MyResultType> MyMethod(){ BusinessResponse<MyResultType> res = new BusinessResponse<MyResultType>(); ProcessResult(res); return res; //this has the values

这对我来说太奇怪了,显然开发人员应该使用关键词out,但我不敢相信这居然有效:

public BusinessResponse<MyResultType> MyMethod(){

    BusinessResponse<MyResultType> res = new BusinessResponse<MyResultType>();
    ProcessResult(res);

    return res; //this has the values set by ProcessResult!!! How?
}

private void ProcessResult(BusinessResponse<MyResultType> result)
{
    result.State = BusinessResponseState.Success;
    //set some other stuff in the result argument
}
public BusinessResponse MyMethod(){
BusinessResponse res=新的BusinessResponse();
处理结果(res);
return res;//这是ProcessResult设置的值!!!如何设置?
}
私有void ProcessResult(BusinessResponse结果)
{
result.State=BusinessResponseState.Success;
//在result参数中设置一些其他内容
}
我的同事说这叫做“深度参考”,我不敢相信这在C#中有效。我想重构以使用
out
aka
private void ProcessResult(out BusinessResponse result)
,但我仍然想知道为什么这段代码有效

更新


所以看起来我是不正确的,这段代码很好。似乎人们的看法是,作为一名C#开发者,我应该马上知道,由于传入processResult的参数是由值传入的堆上的引用类型,因此创建了引用本身的副本,并且复制的引用仍然指向同一对象。

当然,在您的情况下,
BusinessResponse
是一个
类,也称为类。引用类型(对象)总是在C#中“按引用”传递(类似于良好ol'C)1中的指针

这意味着,无论您如何传递引用,它仍然引用内存中的一个实例。这意味着无论你如何引用它,你总是在修改同一个副本

1-这并不完全正确。实际上,引用(变量)是通过值传递的。当函数收到此引用时(同样,请考虑指向托管堆上某个对象的指针),它引用的是同一个对象。但是,引用本身在传入时被复制

我们使用的另一种变量是“值类型”。这些是
struct
s,以及所有的原语,如
char
bool
int
,等等。毫无疑问,它们总是按值传递,这意味着每次将值类型分配给新变量(包括将其传递给函数)时都会生成一个副本。要通过函数调用修改这些内容,必须使用或关键字

那么,您什么时候会对引用类型使用
ref

要更改变量引用的实例时:

public class Foo {
    public string Name { get; private set; }
    public Foo(string name) {
        Name = name;
    }
}

public class Program {

    public static void Example(ref Foo f) {
        // This will print "original"
        Console.WriteLine("Example() was given {0}", f.Name);

        // We assign a new instance to the reference which was
        // passed by reference
        f = new Foo("replacement");
    } 

    public static void Main() {
        Foo f;                       // This variable is a "reference" to a Foo

        f = new Foo("original");     // We assign a new instance to that variable

        Example(ref f);

        // This will print "replacement"
        Console.WriteLine("After calling Example(), f is {0}", f.Name);
    }

}

    • 这需要一点挖掘;您正在发现值类型和引用类型的差异。我不会给你我的两分钱,因为网上已经有这么多了。以下是几篇文章




      最后,MSDN文章

      对象是通过引用传递的。如果这是一种值类型,它将按您所期望的方式工作。啊,当然,谢谢VilvePenguin;)很抱歉,我只是不小心回滚了某人的编辑,不是指删除:您的更新。是的,您只需要(很快)适应这样一个事实,即您在C#中对对象所做的大多数操作都是通过引用完成的。@BrianOgden绝对不是。这意味着完全不同的事情。说引用类型是通过引用传递的是错误的。所有方法参数都是按值传递的,除非您声明该参数为“ref”或“out”。正确的说法是,当按值传递引用类型时,传递的值是引用而不是对象。可以通过值或引用传递值类型,也可以通过值或引用传递引用类型。传递值时,将创建原始值的副本。对于值类型,值是对象;对于引用类型,值是对对象的引用。@jmchiliney您完全正确,我理解其中的区别。但即使对理解你的人来说,你的解释也是令人困惑的。这就是为什么我没有这么说的原因。“为了更好的可读性,最好还是使用关键字out或ref吧?”绝对不是!使用“out”的唯一时间是在未初始化的情况下传入一个参数,然后在方法内直接指定给该参数。使用“ref”的方式与使用“ref”的方式相同,只是参数在传入之前已初始化,并且在方法中使用了初始值。您拥有的代码与它应该的完全一样。你不是在分发一个新的对象;您只是在修改传入的对象。因为它是一个引用类型对象,所以它的工作原理与您(应该)预期的完全一样。@BrianOgden当引用类型(对象)通过
      ref
      /
      out
      传递时,您传递的是对该引用的引用(或指向局部变量的指针)。因此,当在被调用函数中分配该引用(新的/不同的对象)时,调用函数中的原始引用(局部变量)会受到影响。