В чем разница между ключевыми словами ref и out?

это должно помочь: его названное акцентное сгибание:

http://alistapart.com/article/accent-folding-for-auto-complete

828
задан Mechanical snail 8 November 2012 в 02:02
поделиться

10 ответов

ref говорит компилятору, что объект инициализируется прежде, чем ввести функцию, в то время как out говорит компилятору, что объект будет инициализирован в функции.

Поэтому, в то время как ref два пути, out, является единственным.

1100
ответ дан miguel 8 November 2012 в 02:02
поделиться
  • 1
    Так в основном Вы рекомендуете ковровую бомбардировку. Я can' t видят другое решение также.:) – Wabbitseason 2 June 2010 в 15:26

касательно находится в и .

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

28
ответ дан Ruben Bartelink 8 November 2012 в 02:02
поделиться

"Пекарь"

Поэтому первый изменяет Вашу строковую ссылку для указания "Пекарю". Изменение ссылки возможно, потому что Вы передали его через касательно ключевого слова (=> ссылка на ссылку на строку). Второй вызов получает копию ссылки на строку.

строка смотрит некоторое специальное предложение сначала. Но строка является просто классом ссылки и если Вы определяете

string s = "Able";

тогда s, ссылка на строковый класс, который содержит "Способный" текст! Другое присвоение на ту же переменную через

s = "Baker";

не меняет исходную струну, но просто создает новый экземпляр, и позвольте s указать на тот экземпляр!

можно попробовать его следующим небольшим примером кода:

string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);

, Что Вы ожидаете? То, что Вы получите, все еще в состоянии, потому что Вы просто устанавливаете ссылку в s к другому экземпляру, в то время как s2 указывает на исходный экземпляр.

РЕДАКТИРОВАНИЕ: строка также неизменна, что означает, что нет просто никакого метода или свойства, которое изменяет существующий строковый экземпляр (можно попытаться найти один в документах, но Вы не будете пластины никакой:-)). Все методы обработки строк возвращают новый строковый экземпляр! (Вот почему Вы часто получаете лучшую производительность при использовании класса StringBuilder)

6
ответ дан mmmmmmmm 8 November 2012 в 02:02
поделиться
  • 1
    Положительная сторона. Возможно, я должен был разъясниться, как Вы указали, что второй doesn' t работают в случае explicit конструктор. – AraK 17 December 2010 в 13:11

Так как Вы являетесь передающими в ссылочном типе (класс) нет никакого использования потребности ref, потому что на значение по умолчанию только ссылка к фактическому объекту передается, и поэтому Вы всегда изменяете объект позади ссылки.

Пример:

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

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

, Поскольку долго Вы передаете в классе, который Вы не должны использовать ref, если Вы хотите изменить объект в своем методе.

8
ответ дан Albic 8 November 2012 в 02:02
поделиться
  • 1
    Нет. В отправленном коде нет никакого оператора присваивания. – unquiet mind 17 December 2010 в 12:53

ref модификатор означает что:

  1. значение уже установлено и
  2. , метод может считать и изменить его.

out модификатор означает что:

  1. Значение не установлено и не может быть считано методом до , это установлено.
  2. метод должен устанавливать его перед возвратом.
499
ответ дан Agi Hammerthief 8 November 2012 в 02:02
поделиться
  • 1
    you' корректное ре. Я сделал математику и добавил исходный вопрос. – Dinah 16 July 2010 в 19:41

А также разрешение Вам повторно присвоить чужую переменную другому экземпляру класса, возвратите несколько значений и т.д., , использование ref или out сообщает кому-то еще, в чем Вы нуждаетесь от них и что Вы намереваетесь сделать с переменной, которую они обеспечивают

  • , Вам не нужно ref или out, если все, что Вы собираетесь сделать, изменяют вещи внутренний MyClass экземпляр, который передается в аргументе someClass.

    • вызывающий метод будет видеть изменения как someClass.Message = "Hello World", используете ли Вы ref, out или ничто
    • , Запись someClass = new MyClass() внутренний myFunction(someClass) выгружает объект, замеченный someClass в пределах myFunction метод только. Вызывающий метод все еще знает об исходном MyClass экземпляре, который он создал и передал Вашему методу
  • Вы потребность ref или out, если Вы планируете свопинг someClass для совершенно нового объекта и хотите вызывающий метод видеть Ваше изменение

    • Запись someClass = new MyClass() внутренний myFunction(out someClass) изменения объект, замеченный методом, который названный myFunction

Другие программисты существуют

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

  • Используя [1 123] делает оператор "Передачи переменной присвоенный некоторому значению, когда Вы называете мой метод. Знайте, что я мог бы изменить его для чего-то еще полностью в ходе моего метода. Не ожидайте, что Ваша переменная укажет на старый объект, когда я сделан"

  • Используя [1 124], делает оператор "Передачи переменной заполнителя к моему методу. Не имеет значения, имеет ли это значение или нет; компилятор вынудит меня присвоить его новому значению. Я абсолютно гарантирую, что объект, на который указывает Ваша переменная перед вызовом моего метода, , будет отличаться к тому времени, когда я сделан

Между прочим, в C#7.2 существует in модификатор также

, И это препятствует тому, чтобы метод выгрузил переданный в экземпляре для другого экземпляра. Думайте это как высказывание тем миллионам разработчиков "передает меня Ваша исходная ссылка на переменную, и я обещаю не выгрузить Ваши тщательно обработанные данные для чего-то еще". in имеет некоторые особенности и в некоторых случаях такой как, где неявное преобразование могло бы потребоваться, чтобы делать Ваше короткое совместимое с in int, компилятор временно сделает интервал, расширит Ваше короткое до него, передаст его ссылкой и закончится. Это может сделать это, потому что Вы объявили, что не собираетесь смешивать с ним.

<час>

Microsoft сделала это с эти .TryParse методы на числовых типах:

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

Путем установки флага параметра как [1 129] они активно объявляют здесь, "мы определенно попытка изменить кропотливо обработанное значение 98234957 для чего-то еще"

, Конечно, они отчасти имеют к для вещей как парсинг типов значения, потому что, если бы методу синтаксического анализа не позволили выгрузить тип значения для чего-то еще, это не работало бы очень хорошо.. Но предположите, что был некоторый фиктивный метод в некоторой библиотеке, которую Вы создаете:

public void PoorlyNamedMethod(out SomeClass x)

Вы видите, что это out, и можно таким образом знать это при пребывании в течение часов, производя подсчеты, создавая идеальный SomeClass:

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

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

1
ответ дан 22 November 2019 в 21:11
поделиться

Для иллюстрирования многих превосходных объяснений я разработал следующее консольное приложение:

using System;
using System.Collections.Generic;

namespace CSharpDemos
{
  class Program
  {
    static void Main(string[] args)
    {
      List<string> StringList = new List<string> { "Hello" };
      List<string> StringListRef = new List<string> { "Hallo" };

      AppendWorld(StringList);
      Console.WriteLine(StringList[0] + StringList[1]);

      HalloWelt(ref StringListRef);
      Console.WriteLine(StringListRef[0] + StringListRef[1]);

      CiaoMondo(out List<string> StringListOut);
      Console.WriteLine(StringListOut[0] + StringListOut[1]);
    }

    static void AppendWorld(List<string> LiStri)
    {
      LiStri.Add(" World!");
      LiStri = new List<string> { "¡Hola", " Mundo!" };
      Console.WriteLine(LiStri[0] + LiStri[1]);
    }

    static void HalloWelt(ref List<string> LiStriRef)
     { LiStriRef = new List<string> { LiStriRef[0], " Welt!" }; }

    static void CiaoMondo(out List<string> LiStriOut)
     { LiStriOut = new List<string> { "Ciao", " Mondo!" }; }
   }
}
/*Output:
¡Hola Mundo!
Hello World!
Hallo Welt!
Ciao Mondo!
*/
  • AppendWorld: копия StringList названный LiStri передается. В начале метода эта копия ссылается на исходный список и поэтому может использоваться для изменения этого списка. Позже LiStri ссылки другой List<string> объект в методе, который не влияет на исходный список.

  • HalloWelt: LiStriRef уже псевдоним инициализированный ListStringRef. Переданный List<string> объект используется для инициализации нового, поэтому ref было необходимо.

  • CiaoMondo: LiStriOut псевдоним [1 113] и должен быть инициализирован.

Так, если метод просто изменяет объект, на который ссылается переданная переменная, компилятор не позволит Вам использовать out, и Вы не должны использовать ref, потому что это перепутало бы не компилятор, но читателя кода. Если метод сделает ссылку передаваемого аргумента другой объект, используйте ref для уже инициализированного объекта и out для методов, которые должны инициализировать новый объект для передаваемого аргумента. Помимо этого, ref и out ведут себя то же.

1
ответ дан 22 November 2019 в 21:11
поделиться

Допустим, Дом появляется в кабинке Питера по поводу меморандума об отчетах TPS.

Если бы Дом был аргументом ref, у него была бы распечатанная копия служебной записки.

Если бы Дом был неприкрытым аргументом, он заставил бы Питера распечатать новую копию служебной записки, чтобы тот взял с собой.

140
ответ дан 22 November 2019 в 21:11
поделиться

Помните, что эталонный параметр, который передается внутри функция напрямую обрабатывается.

Например,

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

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

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

Здесь будет написано «Собака», а не «Кошка». Следовательно, вы должны напрямую работать с someObject.

-3
ответ дан 22 November 2019 в 21:11
поделиться

Пример расширения собаки и кошки. Второй метод с 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;
    }
13
ответ дан 22 November 2019 в 21:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: