Передача строки ByVal в VB.NET и C # - PullRequest
6 голосов
/ 02 марта 2011

То есть строки являются ссылочными типами, верно?Насколько я понимаю, ссылка на строку в куче передается, даже когда вы передаете строку ByVal методу.

Sooo .....

String myTestValue = "NotModified";
TestMethod(myTestValue);
System.Diagnostics.Debug.Write(myTestValue); /* myTestValue = "NotModified" WTF? */

private void TestMethod(String Value)
{
    Value = "test1";
}

В качестве альтернативы

Dim myTestValue As String = "NotModified"
TestMethod(myTestValue)
Debug.Print(myTestValue) /* myTestValue = "NotModified" WTF? */

Private Sub TestMethod(ByVal Value As String)
    Value = "test1"
End Sub

Чего мне не хватает?А что происходит под капотом?Я бы поспорил в своей жизни, что значение изменилось бы ...

Ответы [ 5 ]

7 голосов
/ 02 марта 2011

Типы ссылок передаются «ссылка по значению» в .NET.Это означает, что присвоение другого значения фактическому параметру фактически не меняет исходного значения (если вы не используете ByRef / ref).Однако все, что вы делаете для изменения фактического объекта, который передается, изменит объект, на который ссылается вызывающий метод.Например, рассмотрим следующую программу:

void Main()
{
    var a = new A{I=1};
    Console.WriteLine(a.I);
    DoSomething(a);
    Console.WriteLine(a.I);
    DoSomethingElse(a);
    Console.WriteLine(a.I);
}

public void DoSomething(A a)
{
    a = new A{I=2};
}

public void DoSomethingElse(A a)
{
    a.I = 2;
}

public class A
{
    public int I;
}

Вывод:

1
1
2

Метод DoSomething назначил своему параметру a другое значение, но этот параметр простолокальный указатель на местоположение оригинала a из вызывающего метода.Изменение значения указателя ничего не изменило для изменения значения a вызывающего метода.Однако DoSomethingElse фактически внес изменение в одно из значений в объекте, на который ссылаются.

Независимо от того, что говорят другие ответчики, string не является исключительным в этом смысле.Все объекты ведут себя таким образом.

Где string отличается от многих объектов тем, что он неизменен: там нет никаких методов или свойств или полей в строке, которые вы можете вызвать на самом делеизменить строку.Как только строка создается в .NET, она доступна только для чтения.

Когда вы делаете что-то вроде этого:

var s = "hello";
s += " world";

... компилятор превращает это в нечто вроде этого:

// this is compiled into the assembly, and doesn't need to be set at runtime.
const string S1 = "hello"; 
const string S2 = " world"; // likewise
string s = S1;
s = new StringBuilder().Append(s).Append(S2).ToString();

Эта последняя строка генерирует новую строку, но S1 и S2 все еще находятся вокруг.Если они являются постоянными строками, встроенными в сборку, они останутся там.Если они были созданы динамически и на них больше нет ссылок, сборщик мусора может отменить их, чтобы освободить память.Но ключ должен понять, что S1 фактически никогда не изменялся.Переменная, указывающая на нее, просто изменилась, чтобы указывать на другую строку.

3 голосов
/ 02 марта 2011

Все передается по значению, если не указано иное.Когда вы передаете строку, вы фактически передаете ссылку по значению.

Для строк это не имеет большого значения, поскольку строки являются неизменяемыми.Это означает, что вы никогда не сможете изменить полученную строку.Для других классов, однако, вы можете изменить объект, переданный по значению (если, как и String, он не является неизменным).То, что вы не можете сделать и что позволяет передавать по ссылке, это изменить переменную , которую вы передаете.

Пример:

Public Class Example
    Private Shared Sub ExampleByValue(ByVal arg as String)
        arg = "ByVal args can be modifiable, but can't be replaced."
    End Sub

    Private Shared Sub ExampleByRef(ByRef arg as String)
        arg = "ByRef args can be set to a whole other object, if you want."
    End Sub

    Public Shared Sub Main()
        Dim s as String = ""
        ExampleByValue(s)
        Console.WriteLine(s)  ''// This will print an empty line
        ExampleByRef(s)
        Console.WriteLine(s)  ''// This will print our lesson for today
    End Sub
End Class

Сейчас, это должно использоваться очень экономно, потому что значение по умолчанию является ожидаемым.Особенно в VB, который не всегда проясняет, когда вы передаете по ссылке, он может вызвать много проблем, когда какой-то метод неожиданно начинает перебирать ваши переменные.

2 голосов
/ 02 марта 2011

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

Только когда вы изменяете объект, который передается по значению, эффект может быть виден вне метода. Конечно, строки являются неизменяемыми, поэтому здесь это на самом деле не применимо.

0 голосов
/ 02 марта 2011
  1. Когда вы передаете строку в метод, берется копия ссылки. Таким образом, Value - это целая новая переменная, которая все еще ссылается на ту же строку в памяти.
  2. Строковый литерал "test" также создается как реальный объект ссылочного типа. Это не просто значение в вашем исходном коде.
  3. Когда вы присваиваете "test" для Value, ссылка для вашей переменной Value обновляется, чтобы ссылаться на "test" вместо исходной строки. Поскольку эта ссылка является просто копией (как мы видели в шаге 1), переменная myTestValue вне функции остается неизменной и по-прежнему ссылается на исходную строку.

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

0 голосов
/ 02 марта 2011

Вы передаете копию, а не реальную ссылку.

прочитайте эту статью от Microsoft

http://msdn.microsoft.com/en-us/library/s6938f28.aspx

...