programing

C# 문자열 참조 유형?

bestprogram 2023. 9. 9. 09:46

C# 문자열 참조 유형?

C#의 "string"이 참조형인 것으로 알고 있습니다.이것은 MSDN에 있습니다. 그러나 이 코드는 작동하지 않습니다.

class Test
{
    public static void Main()
    {
        string test = "before passing";
        Console.WriteLine(test);
        TestI(test);
        Console.WriteLine(test);
    }

    public static void TestI(string test)
    {
        test = "after passing";
    }
}

문자열을 매개 변수로 전달하고 있으며 참조 유형이므로 두 번째 출력 문은 Test I 방법에서 텍스트가 변경되었음을 인식해야 하므로 "통과 후" 출력이 "통과 전"이어야 합니다.하지만 저는 "합격하기 전"에 "합격하기 전"을 받아서 ref가 아닌 value로 합격한 것처럼 보입니다.끈은 불변이라는 것은 이해하지만, 무슨 일이 일어나고 있는지 어떻게 설명할 수 있을지 모르겠습니다.제가 무엇을 빠뜨리고 있나요?감사해요.

문자열에 대한 참조가 값으로 전달됩니다.기준을 값 단위로 통과시키는 것과 기준 단위로 통과시키는 것은 큰 차이가 있습니다.두 경우 모두 '참조'라는 단어가 사용되는 것은 유감스러운 일입니다.

문자열 참조를 참조로 전달하면 다음과 같이 작동합니다.

using System;

class Test
{
    public static void Main()
    {
        string test = "before passing";
        Console.WriteLine(test);
        TestI(ref test);
        Console.WriteLine(test);
    }

    public static void TestI(ref string test)
    {
        test = "after passing";
    }
}

이제 참조가 참조하는 개체를 변경하는 것과 변수(예: 매개 변수)를 변경하여 다른 개체를 참조하도록 하는 것을 구별해야 합니다.문자열은 불변이기 때문에 문자열을 변경할 수는 없지만 다음과 같이 시연할 수 있습니다.StringBuilder대신:

using System;
using System.Text;

class Test
{
    public static void Main()
    {
        StringBuilder test = new StringBuilder();
        Console.WriteLine(test);
        TestI(test);
        Console.WriteLine(test);
    }

    public static void TestI(StringBuilder test)
    {
        // Note that we're not changing the value
        // of the "test" parameter - we're changing
        // the data in the object it's referring to
        test.Append("changing");
    }
}

자세한 내용은 매개변수 전달에 대한기사를 참조해 주세요.

만약 우리가 질문에 대답해야 한다면:문자열은 참조 유형이며 참조로 동작합니다.실제 문자열이 아닌 참조를 유지하는 매개 변수를 전달합니다.문제는 다음 기능에 있습니다.

public static void TestI(string test)
{
    test = "after passing";
}

δtest문자열에 대한 참조를 보유하지만 복사본입니다.문자열을 가리키는 변수가 두 개 있습니다.문자열을 사용하는 모든 작업은 실제로 새로운 개체를 생성하기 때문에 새 문자열을 가리키도록 로컬 복사본을 만듭니다.test변수는 변경되지 않습니다.

제안된 해결책은 다음과 같습니다.ref그지을기에수과출서을출feeeneesrt그enenlknn을d수v지에을이기test합니다.만만다다만e만statlt .따라서 함수 내부의 모든 변경 사항은 원래 변수를 반영합니다.

. 합니다행입니다. 문자열은 참조 유형이지만 불변이므로 행을 반복합니다.test = "after passing";로운의을다와fye을로y의as운re와dttest가 새 문자열을 가리키도록 변경됩니다.

다른 바와 , 이,String치다는 값으로됩니다.NET은 불변이며 그 참조는 값으로 전달됩니다.

원래 코드에서 이 줄이 실행되는 즉시 다음을 수행합니다.

test = "after passing";

그리고나서test이상 원래 개체를 참조하지 않습니다.우리는 새로운 것을 만들었습니다. String 및 체및됨dtest관리되는 힙에서 해당 개체를 참조합니다.

눈에 잘 띄는 정식 시공자가 없어서 많은 사람들이 여기서 발을 헛디디는 것 같습니다.이번 사건은 그 사건 이후로 막후에서 벌어지고 있습니다.Stringtype은 그것이 구성되는 방법에 언어 지원이 있습니다.

, 이 가 의 가 의 이 으로test의위는볼수다수feeeseet볼의위는feTestI(string)method 을 넘겼는데 이 바뀌었군요을 -로데제그다이d다!이그d-을로제데-de!'d!하지만 만약에String고해을때는을위다서볼fe볼eee서위te을ee는l가는,de,때에ynee되었고TestI(string)방법.

경우 reforout 키워드가 필요합니다.저는 키워드가 이 특정한 상황에 조금 더 적합할 수 있다고 생각합니다.

class Program
{
    static void Main(string[] args)
    {
        string test = "before passing";
        Console.WriteLine(test);
        TestI(out test);
        Console.WriteLine(test);
        Console.ReadLine();
    }

    public static void TestI(out string test)
    {
        test = "after passing";
    }
}

"한 장의 그림이 천 마디 말의 가치가 있습니다."

여기 간단한 예가 있는데, 당신의 경우와 비슷합니다.

string s1 = "abc";
string s2 = s1;
s1 = "def";
Console.WriteLine(s2);
// Output: abc

이런 일이 벌어졌습니다.

enter image description here

  • 1호선과 2호선:s1그리고.s2한조"abc"문자열 개체입니다.
  • 줄 3: 문자열은 불변이기 때문에"abc"는 자체(열가를지다상상다 ( )로)."def"), 그러나 새로운"def"열가신된음음g신s1그것에 대한 언급.
  • 4호선:s2에 대한 여전한 언급"abc"문자열 개체가 출력됩니다.

사실, 참조 유형이 되는 것과 참조를 통과하는 것은 c#에서 두 가지 다른 것이라는 것은 어떤 물체에 대해서도 동일했을 것입니다.

이 방법은 효과가 있지만 유형에 관계없이 적용됩니다.

public static void TestI(ref string test)

또한 문자열이 참조형인 것에 대해서도 특별한 것입니다.이것은 불변하도록 설계되어 있어서, 모든 메소드가 인스턴스를 수정하지는 않습니다(새로운 메소드를 반환합니다).또한 성능을 위해 추가적인 것들이 들어있습니다.

값 유형, 값별 전달, 참조 유형 및 참조별 전달 간의 차이를 생각해 볼 수 있는 좋은 방법은 다음과 같습니다.

변수는 컨테이너입니다.

값 유형 변수에 인스턴스가 포함되어 있습니다.참조 유형 변수에는 다른 곳에 저장된 인스턴스에 대한 포인터가 들어 있습니다.

값 유형 변수를 수정하면 포함된 인스턴스가 변형됩니다.참조 유형 변수를 수정하면 해당 변수가 가리키는 인스턴스가 변형됩니다.

별도의 참조 유형 변수가 동일한 인스턴스를 가리킬 수 있습니다.따라서 동일한 인스턴스는 해당 인스턴스를 가리키는 변수를 통해 변형될 수 있습니다.

passed by value 인수는 내용의 새 복사본이 있는 새 컨테이너입니다.전달된 참조 인수는 원래 내용이 있는 원래 컨테이너입니다.

value-type 인수가 값 단위로 전달되는 경우:컨테이너가 고유하기 때문에 인수의 내용을 재할당해도 범위를 벗어난 영향은 없습니다.인스턴스가 독립적인 복사본이기 때문에 인수를 수정해도 범위를 벗어난 효과는 없습니다.

참조 유형 인수가 값 단위로 전달되는 경우:컨테이너가 고유하기 때문에 인수의 내용을 재할당해도 범위를 벗어난 영향은 없습니다.복사된 포인터가 공유 인스턴스를 가리키기 때문에 인수의 내용을 수정하면 외부 범위에 영향을 미칩니다.

인수가 참조로 전달될 경우:컨테이너가 공유되고 있기 때문에 인수의 내용을 재할당하면 외부 범위에 영향을 미칩니다.내용이 공유되므로 인수의 내용을 수정하면 외부 범위에 영향을 미칩니다.

결론:

문자열 변수는 참조 유형 변수입니다.따라서 다른 곳에 저장된 인스턴스에 대한 포인터를 포함합니다.값별로 전달되면 포인터가 복사되므로 문자열 인수를 수정하면 공유 인스턴스에 영향을 미칩니다.그러나 문자열 인스턴스에는 가변 속성이 없으므로 문자열 인수를 수정할 수 없습니다.참조로 전달된 경우 포인터의 컨테이너가 공유되므로 재할당은 여전히 외부 범위에 영향을 미칩니다.

위의 답변이 도움이 됩니다. ref 키워드 없이 매개 변수를 전달할 때 해당 매개 변수가 참조 유형인 경우에도 어떤 일이 발생하는지 명확하게 보여주는 예를 추가하고자 합니다.

MyClass c = new MyClass(); c.MyProperty = "foo";

CNull(c); // only a copy of the reference is sent 
Console.WriteLine(c.MyProperty); // still foo, we only made the copy null
CPropertyChange(c); 
Console.WriteLine(c.MyProperty); // bar


private void CNull(MyClass c2)
        {          
            c2 = null;
        }
private void CPropertyChange(MyClass c2) 
        {
            c2.MyProperty = "bar"; // c2 is a copy, but it refers to the same object that c does (on heap) and modified property would appear on c.MyProperty as well.
        }

호기심이 많은 사람들과 대화를 끝마치려면:예, 문자열은 참조 유형입니다.

unsafe
{
     string a = "Test";
     string b = a;
     fixed (char* p = a)
     {
          p[0] = 'B';
     }
     Console.WriteLine(a); // output: "Best"
     Console.WriteLine(b); // output: "Best"
}

그러나 이 변경 사항은 안전하지 않은 블록에서만 작동합니다! 문자열은 불변이므로(MSDN에서):

문자열 개체의 내용은 개체를 만든 후에는 변경할 수 없지만 구문을 사용하면 이 작업을 수행할 수 있는 것처럼 표시됩니다.예를 들어, 이 코드를 쓸 때 컴파일러는 실제로 새로운 문자열 개체를 만들어 새로운 문자 시퀀스를 유지하고, 그 새로운 개체는 b에 할당됩니다.그러면 문자열 "h"는 가비지 수집에 적합합니다.

string b = "h";  
b += "ello";  

그리고 명심해야 할 것은:

연산자 이지만 ( )==그리고.!=참조가 아닌 문자열 개체의 값을 비교하도록 정의됩니다.

시도:


public static void TestI(ref string test)
    {
        test = "after passing";
    }

당신의 코드가 다음과 유사하다고 생각하며, 당신은 여기에 있지 않은 것과 같은 이유로 값이 변할 것이라고 예상하지 말았어야 했습니다.

 public static void Main()
 {
     StringWrapper testVariable = new StringWrapper("before passing");
     Console.WriteLine(testVariable);
     TestI(testVariable);
     Console.WriteLine(testVariable);
 }

 public static void TestI(StringWrapper testParameter)
 {
     testParameter = new StringWrapper("after passing");

     // this will change the object that testParameter is pointing/referring
     // to but it doesn't change testVariable unless you use a reference
     // parameter as indicated in other answers
 }

문자열 동작을 우회하는 또 다른 방법입니다.하나의 요소의 문자열 배열만 사용하고 이 요소를 조작합니다.

class Test
{
    public static void Main()
    {
        string[] test = new string[1] {"before passing"};
        Console.WriteLine(ref test);
        TestI(test);
        Console.WriteLine(ref test);
    }

    public static void TestI(ref string[] test)
    {
        test[0] = "after passing";
    }
}

언급URL : https://stackoverflow.com/questions/1096449/c-sharp-string-reference-type