我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:

public void myFunction(ref MyClass someClass)

and

public void myFunction(out MyClass someClass)

我应该用哪个,为什么?


当前回答

对于那些以身作则的人(比如我),以下是安东尼·科索夫所说的。

我创建了一些ref、out和其他例子来说明这一点。我并没有介绍最佳实践,只是举例来理解它们之间的差异。

https://gist.github.com/2upmedia/6d98a57b68d849ee7091

其他回答

 public static void Main(string[] args)
    {
        //int a=10;
        //change(ref a);
        //Console.WriteLine(a);
        // Console.Read();

        int b;
        change2(out b);
        Console.WriteLine(b);
        Console.Read();
    }
    // static void change(ref int a)
    //{
    //    a = 20;
    //}

     static void change2(out int b)
     {
         b = 20;
     }

你可以检查这段代码,它会向你描述它的完全不同 当你使用“ref”时,这意味着你已经初始化了int/string

但 当你使用out的时候 无论你是否初始化int/string,它都适用于这两种情况 但是u必须在函数中初始化int/string

扩展狗和猫的例子。带有ref的第二个方法更改调用者引用的对象。所以叫“猫”!!

    public static void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog". 
        Bar(ref myObject);
        Console.WriteLine(myObject.Name); // Writes "Cat". 
    }

    public static void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

    public static void Bar(ref MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

下面是一个同时使用Ref和out的例子。现在,你们都可以离开裁判了。

在下面提到的例子中,当我注释//myRefObj = new myClass {Name = "ref outside called!! ""}; 行,将得到一个错误说“使用未分配的局部变量'myRefObj'”,但没有这样的错误在out。

在哪里使用Ref:当我们调用带有in形参的过程时,该形参将用于存储该过程的输出。

在哪里使用Out:当我们调用一个没有in形参的过程时,相同的参数将用于返回该过程的值。 还要注意输出

public partial class refAndOutUse : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        myClass myRefObj;
        myRefObj = new myClass { Name = "ref outside called!!  <br/>" };
        myRefFunction(ref myRefObj);
        Response.Write(myRefObj.Name); //ref inside function

        myClass myOutObj;
        myOutFunction(out myOutObj);
        Response.Write(myOutObj.Name); //out inside function
    }

    void myRefFunction(ref myClass refObj)
    {
        refObj.Name = "ref inside function <br/>";
        Response.Write(refObj.Name); //ref inside function
    }
    void myOutFunction(out myClass outObj)
    {
        outObj = new myClass { Name = "out inside function <br/>" }; 
        Response.Write(outObj.Name); //out inside function
    }
}

public class myClass
{
    public string Name { get; set; }
} 

除了允许你将别人的变量重新分配给类的不同实例,返回多个值等,使用ref或out可以让别人知道你需要从他们那里得到什么,以及你打算用他们提供的变量做什么

You don't need ref or out if all you're going to do is modify things inside the MyClass instance that is passed in the argument someClass. The calling method will see changes like someClass.Message = "Hello World" whether you use ref, out or nothing Writing someClass = new MyClass() inside myFunction(someClass) swaps out the object seen by the someClass in the scope of the myFunction method only. The calling method still knows about the original MyClass instance it created and passed to your method You need ref or out if you plan on swapping the someClass out for a whole new object and want the calling method to see your change Writing someClass = new MyClass() inside myFunction(out someClass) changes the object seen by the method that called myFunction

还有其他程序员

他们想知道你将如何处理他们的数据。假设您正在编写一个将被数百万开发人员使用的库。你想让他们知道当他们调用你的方法时你要对他们的变量做什么

Using ref makes a statement of "Pass a variable assigned to some value when you call my method. Be aware that I might change it out for something else entirely during the course of my method. Do not expect your variable to be pointing to the old object when I'm done" Using out makes a statement of "Pass a placeholder variable to my method. It doesn't matter whether it has a value or not; the compiler will force me to assign it to a new value. I absolutely guarantee that the object pointed to by your variable before you called my method, will be different by the time I'm done

顺便说一下,在c# 7.2中也有一个in修饰符

And that prevents the method from swapping out the passed in instance for a different instance. Think of it like saying to those millions of developers "pass me your original variable reference, and I promise not to swap your carefully crafted data out for something else". in has some peculiarities, and in some cases such as where an implicit conversion might be required to make your short compatible with an in int the compiler will temporarily make an int, widen your short to it, pass it by reference and finish up. It can do this because you've declared you're not going to mess with it.


微软对数值类型的.TryParse方法做到了这一点:

int i = 98234957;
bool success = int.TryParse("123", out i);

通过将参数标记为out他们在这里积极地声明"我们肯定会将你苦心制作的98234957值更改为其他值"

当然,对于像解析值类型这样的事情,它们有点不得不这样做,因为如果parse方法不允许将值类型替换为其他类型,那么它就不能很好地工作。但是想象一下在你创建的库中有一些虚构的方法:

public void PoorlyNamedMethod(out SomeClass x)

你可以看到它是一个out,因此你可以知道,如果你花了几个小时处理数字,创建一个完美的SomeClass:

SomeClass x = SpendHoursMakingMeAPerfectSomeClass();
//now give it to the library
PoorlyNamedMethod(out x);

那真是浪费时间,花那么多时间来做一节完美的课。它肯定会被丢弃,并被PoorlyNamedMethod取代

如果你想将参数作为引用传递,那么你应该在将参数传递给函数之前初始化它,否则编译器本身会显示错误。但是对于out形参,您不需要在将对象形参传递给方法之前初始化它。可以在调用方法本身中初始化对象。