IT박스

C # 구조체가 변경 불가능한 이유는 무엇입니까?

itboxs 2021. 1. 6. 07:55
반응형

C # 구조체가 변경 불가능한 이유는 무엇입니까?


왜 구조체, 문자열 등이 변경 불가능한지 궁금했습니다. 그것들을 불변으로 만들고 나머지 객체를 변경 가능하게 만드는 이유는 무엇입니까? 객체를 불변으로 만드는 것으로 간주되는 것은 무엇입니까?

변경 가능한 객체와 변경 불가능한 객체에 대해 메모리가 할당되고 할당 해제되는 방식에 차이가 있습니까?


이 주제에 관심이 있으시면 http://blogs.msdn.com/b/ericlippert/archive/tags/immutability/ 에 변경 불가능한 프로그래밍에 대한 여러 기사가 있습니다.

왜 구조체, 문자열 등이 변경 불가능한지 궁금했습니다.

구조체와 클래스는 기본적으로 변경할 수 없지만 구조체를 변경 불가능하게 만드는 것이 가장 좋습니다. 나는 불변 클래스도 좋아합니다.

문자열은 변경할 수 없습니다.

그것들을 불변으로 만들고 나머지 객체를 변경 가능하게 만드는 이유는 무엇입니까?

모든 유형을 변경 불가능하게 만드는 이유 :

  • 변경되지 않는 객체에 대해 추론하는 것이 더 쉽습니다. 3 개의 항목이있는 대기열이있는 경우 지금 비어 있지 않고 5 분 전에 비어 있지 않았으며 앞으로도 비어 있지 않을 것입니다. 불변입니다! 사실을 알게되면 그 사실을 영원히 사용할 수 있습니다. 불변 객체에 대한 사실은 오래되지 않습니다.

  • 첫 번째 요점의 특별한 경우 : 변경 불가능한 객체는 스레드를 안전하게 만드는 것이 훨씬 쉽습니다. 대부분의 스레드 안전 문제는 한 스레드에 대한 쓰기와 다른 스레드에 대한 읽기 때문입니다. 불변 객체에는 쓰기가 없습니다.

  • 변경 불가능한 객체는 분리하여 재사용 할 수 있습니다. 예를 들어 변경 불가능한 이진 트리가있는 경우 왼쪽 및 오른쪽 하위 트리를 걱정하지 않고 다른 트리 의 하위 트리로 사용할 수 있습니다 . 변경 가능한 구조에서는 일반적으로 하나의 논리적 객체에 대한 변경 사항이 다른 논리적 객체에 영향을 미치는 것을 원하지 않기 때문에 데이터를 다시 사용하기 위해 복사본을 만듭니다. 이것은 많은 시간과 메모리를 절약 할 수 있습니다 .

구조체를 불변으로 만드는 이유

구조체를 불변으로 만드는 데는 많은 이유가 있습니다. 여기 하나만 있습니다.

구조체는 참조가 아닌 값으로 복사됩니다. 실수로 구조체를 참조로 복사 된 것으로 취급하는 것은 쉽습니다. 예를 들면 :

void M()
{
    S s = whatever;
    ... lots of code ...
    s.Mutate();
    ... lots more code ...
    Console.WriteLine(s.Foo);
    ...
}

이제 해당 코드 중 일부를 도우미 메서드로 리팩터링하려고합니다.

void Helper(S s)
{
    ... lots of code ...
    s.Mutate();
    ... lots more code ...
}

잘못된! 그것은 (ref S s)이어야합니다-그렇게하지 않으면 s 복사본 에서 변이가 일어날 것입니다 . 처음에 돌연변이를 허용하지 않으면 이러한 모든 종류의 문제가 사라집니다.

문자열을 불변으로 만드는 이유

사실을 유지하는 불변 구조에 대한 사실에 대한 첫 번째 요점을 기억하십니까?

문자열이 변경 가능하다고 가정합니다.

public static File OpenFile(string filename)
{
    if (!HasPermission(filename)) throw new SecurityException();
    return InternalOpenFile(filename);
}

적대적인 호출자 가 보안 검사 파일을 열기 전에 파일 이름 변경하면 어떻게 됩니까? 코드가 권한이없는 파일을 열었습니다!

다시 말하지만, 변경 가능한 데이터는 추론하기 어렵습니다. "이 호출자는이 문자열이 설명하는 파일을 볼 수있는 권한이 있습니다"라는 사실이 변이가 발생할 때까지가 아니라 영원히 참이되기를 원합니다 . 변경 가능한 문자열을 사용하여 보안 코드를 작성하려면 변경되지 않는 데이터의 복사본을 지속적으로 만들어야합니다.

객체를 불변으로 만드는 것으로 간주되는 것은 무엇입니까?

유형이 논리적으로 "영원한"값을 나타내는가? 숫자 12는 숫자 12입니다. 그것은 변하지 않습니다. 정수는 불변이어야합니다. 점 (10, 30)은 점 (10, 30)입니다. 그것은 변하지 않습니다. 포인트는 불변이어야합니다. 문자열 "abc"는 문자열 "abc"입니다. 그것은 변하지 않습니다. 문자열은 불변이어야합니다. 목록 (10, 20, 30)은 변경되지 않습니다. 등등.

때로는 유형이 변경되는 것을 나타냅니다. Mary Smith의 성은 Smith이지만 내일은 Mary Jones가 될 수 있습니다. 아니면 오늘 미스 스미스가 내일 스미스 박사가 될 수도 있습니다. 외계인은 현재 50 개의 체력 포인트를 가지고 있지만 레이저 빔에 맞은 후 10 개를 가지고 있습니다. 어떤 것들은 돌연변이로 가장 잘 표현됩니다.

변경 가능한 객체와 변경 불가능한 객체에 대해 메모리가 할당되고 할당 해제되는 방식에 차이가 있습니까?

그렇지 않습니다. 앞서 언급했듯이 불변 값의 좋은 점 중 하나는 복사본을 만들지 않고도 일부를 재사용 할 수 있다는 것입니다. 따라서 그런 의미에서 메모리 할당은 매우 다를 수 있습니다.


Structs not ... 이것이 가변 구조체가 나쁜 이유입니다.

Creating mutable structs can lead to all kinds of strange behavior in your application and, therefore, they are considered a very bad idea (stemming from the fact that they look like a reference type but are actually a value type and will be copied whenever you pass them around).

Strings, on the other hand, are. This makes them inherently thread-safe as well as allowing for optimizations via string interning. If you need to construct a complicated string on the fly, you can use StringBuilder.


The concepts of mutability and immutability have different meanings when applied to structs and classes. A key aspect (oftentimes, the key weakness) of mutable classes is if Foo has a field Bar of type List<Integer>, which holds a reference to a list containing (1,2,3), other code which has a reference to that same list could modify it, such that Bar holds a reference to a list containing (4,5,6), even if that other code has no access whatsoever to Bar. By contrast, if Foo had a field Biz of type System.Drawing.Point, the only way anything could modify any aspect of Biz would be to have write access to that field.

The fields (public and private) of a struct can be mutated by any code which can mutate the storage location in which the struct is stored, and cannot be mutated by any code which cannot mutate the storage location where it is stored. If all of the information encapsulated within a struct is held in its fields, such a struct can effectively combine the control of an immutable type with the convenience of a mutable type, unless the struct is coded in such a way as to remove such convenience (a habit which, unfortunately, some Microsoft programmers recommend).

The "problem" with structs is that when a method (including a property implementation) is invoked on a struct in a read-only context (or immutable location), the system copies the struct, performs the method on the temporary copy, and silently discards the result. This behavior has led programmers to put forth the unfortunate notion that the way to avoid problems with mutating methods is to have many structs disallow piecewise updates, when the problems could have been better avoided by simply replacing properties with exposed fields.

Incidentally, some people complain that when a class property returns a conveniently-mutable struct, changes to the struct don't affect the class from which it came. I would posit that's a good thing--the fact that the returned item is a struct makes the behavior clear (especially if it's an exposed-field struct). Compare a snippet using a hypothetical struct and property on Drawing.Matrix with one using an actual property on that class as implemented by Microsoft:

// Hypothetical struct
public struct {
  public float xx,xy,yx,yy,dx,dy;
} Transform2d;

// Hypothetical property of "System.Drawing.Drawing2d.Matrix"
public Transform2d Transform {get;}

// Actual property of "System.Drawing.Drawing2d.Matrix"
public float[] Elements { get; }

// Code using hypothetical struct
Transform2d myTransform = myMatrix.Transform;
myTransform.dx += 20;
... other code using myTransform

// Code using actual Microsoft property
float[] myArray = myMatrix.Elements;
myArray[4] += 20;
... other code using myArray

Looking at the actual Microsoft property, is there any way to tell whether the write to myArray[4] will affect myMatrix? Even looking at the page http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.matrix.elements.aspx is there any way to tell? If the property had been written using the struct-based equivalent, there would be no confusion; the property that returns the struct would return nothing more nor less than the present value of six numbers. Changing myTransform.dx would be nothing more nor less than a write to a floating-point variable which was unattached to anything else. Anyone who doesn't like the fact that changing myTransform.dx doesn't affect myMatrix should be equally annoyed that writing myArray[4] doesn't affect myMatrix either, except that the independence of myMatrix and myTransform is apparent, while the independence of myMatrix and myArray is not.


A struct type is not immutable. Yes, strings are. Making your own type immutable is easy, simply don't provide a default constructor, make all fields private and define no methods or properties that change a field value. Have a method that should mutate the object return a new object instead. There is a memory management angle, you tend to create a lot of copies and garbage.


Structs can be mutable, but it's a bad idea because they have copy-semantics. If you make a change to a struct, you might actually be modifying a copy. Keeping track of exactly what has been changed is very tricky.

Mutable structs breed mistakes.

ReferenceURL : https://stackoverflow.com/questions/3751911/why-are-c-sharp-structs-immutable

반응형