Предоставляет ли С# список <T> методу по ссылке или в качестве копии?

Принимая мои первые шаги в С# мире от C/С++, так что немного туманно в деталях. Классы, насколько я понял, передаются по ссылке по умолчанию, но как насчет, например. Список < строка > как в:

void DoStuff(List<string> strs)
{
    //do stuff with the list of strings
}

и в других местах

List<string> sl = new List<string>();
//next fill list in a loop etc. and then do stuff with it:
DoStuff(sl);

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

void DoStuff(ref List<string> strs)
, чтобы фактически действовать на sl а не копией?

Ответ 1

Он прошел по ссылке. List<T> - это класс, и все экземпляры класса передаются по ссылке.

Ответ 2

Поведение всегда одно и то же: передача путем копирования. В случае, если параметр является объектом, ссылка на объект копируется, поэтому на самом деле вы работаете над одним и тем же объектом/списком/независимо.

Ответ 3

В основе всего всегда: типы значений передаются по значению, а ссылочные типы "передаются по ссылке" (цитируются, потому что значение ссылки фактически передается по значению, но большинство людей игнорируют это ради краткости).

Самый простой способ сопоставить ключевое слово ref с ссылками: ссылочные типы имеют ссылку, переданную по значению. Это означает, что в стандартном случае просто передать ссылку на список (а не весь список) на метод.

Ключевое слово ref, когда оно используется в ссылочном типе, семантически передает ссылку на ссылку (я действительно не могу сказать "указатель на указатель" ).

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

Вышеприведенное объяснение бесстыдно взято из статьи Джона Скита по теме:

Это различие абсолютно важно для понимания параметра переходя в С#, и именно поэтому я считаю, что очень сложно сказать, что объекты передаются по ссылке по умолчанию вместо правильного что ссылки на объекты передаются по умолчанию по умолчанию.

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

void DoSomething(List<string> strs) 
{ 
    strs.Add("Hello");
}

Ответ 4

В дополнение к другим ответам очень важно понять поведение ref

Вот пример кода для демонстрационной цели

static void Main(string[] args)
    {

        List<string> lstStr = new List<string>();

        lstStr.Add("First");
        lstStr.Add("Second");

        Alter(lstStr);

        //Alter(ref lstStr);

        Console.WriteLine("---From Main---");
        foreach (string s in lstStr)
        {
            Console.WriteLine(s);
        }

        Alter2(ref lstStr);

        Console.WriteLine("---From Main after passed by ref---");
        foreach (string s in lstStr)
        {
            Console.WriteLine(s);
        }

        Console.ReadKey();
    }

    static void Alter(List<string> lstStr2)
    {
        lstStr2.Add("Third");

        Console.WriteLine("----From Alter----");
        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

        lstStr2 = new List<string>();
        lstStr2.Add("Something new");

        Console.WriteLine("----From Alter - after the local var is assigned somthing else----");

        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

    }

    static void Alter2(ref List<string> lstStr2)
    {
        lstStr2 = new List<string>();
        lstStr2.Add("Something new from alter 2");

        Console.WriteLine("----From Alter2 - after the local var is assigned new list----");

        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

    }


//----From Alter----
//First
//Second
//Third
//----From Alter - after the local var is assigned somthing else----
// Something new
// ---From Main---
// First
// Second
// Third
// ----From Alter2 - after the local var is assigned new list----
// Something new from alter 2
// ---From Main after passed by ref---
// Something new from alter 2

Ответ 5

Список передается по ссылке. Фактически это означает, что переменная strs внутри метода относится к тому же списку, что и переменная sl вне метода. Если вы будете использовать ref, вы можете переназначить переменную sl внутри метода.

strs = new List<string>()

сделает sl точкой в ​​новом списке.

Поскольку вы исходите из C/С++: ref может считаться "безопасным указателем". Это похоже на использование & strs

Ответ 6

Ключевое слово ref в вашем методе является избыточным, если вы хотите изменить исходный список: List<T> является ссылочным типом (class в С#) и поэтому будет передан методу посредством ссылки; поэтому метод будет управлять исходным списком.

При передаче Value Type он создаст копию самого значения. При передаче Reference Type он создаст копию справки.

Подробнее о Типы значений и ссылок на С#.

Ответ 7

Его по ссылке. Не обязательно включать "ref".

С уважением.