클래스 또는 구조체 정의는 형식이 수행할 수 있는 작업을 지정하는 청사진과 같습니다. 개체는 프로그램이 청사진에 따라 할당하고 구성하는 메모리 블록입니다. 프로그램은 동일한 클래스의 많은 개체를 만들 수 있습니다. 개체 인스턴스를 호출할 수도 있습니다. 명명된 변수 또는 배열 또는 컬렉션에 저장할 수 있습니다. 클라이언트 코드는 이러한 변수를 사용하여 메서드를 호출하고 개체의 공용 속성에 액세스합니다. C#과 같은 개체 지향 언어에서 일반적인 프로그램은 동적으로 상호 작용하는 여러 개체로 구성됩니다.
비고
정적 형식은 이 문서에 설명된 것과 다르게 동작합니다. 자세한 내용은 static 클래스 및 static 클래스 멤버를 참조하세요.
구조체 인스턴스 및 클래스 인스턴스
클래스는 참조 형식이므로 클래스 개체의 변수는 관리되는 힙에 있는 개체의 주소에 대한 참조를 보유합니다. 동일한 형식의 두 번째 변수를 첫 번째 변수에 할당하는 경우 두 변수 모두 해당 주소의 개체를 참조합니다. 이 문서에서는 이 사항에 대해 나중에 자세히 설명합니다.
연산자를 사용하여 클래스의 인스턴스를 만듭니다new. 다음 예제에서 Person 형식이고 person1person2 해당 형식의 인스턴스 또는 개체입니다.
using System;
public class Person(string name, int age)
{
public string Name { get; set; } = name;
public int Age { get; set; } = age;
// Other properties, methods, events...
}
class Program
{
static void Main()
{
Person person1 = new("Leopold", 6);
Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");
// Declare new person, assign person1 to it.
Person person2 = person1;
// Change the name of person2, and person1 also changes.
person2.Name = "Molly";
person2.Age = 16;
Console.WriteLine($"person2 Name = {person2.Name} Age = {person2.Age}");
Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");
/*
Output:
person1 Name = Leopold Age = 6
person2 Name = Molly Age = 16
person1 Name = Molly Age = 16
*/
}
}
구조체는 값 형식이므로 구조체 개체의 변수는 전체 개체의 복사본을 보유합니다. 연산자를 사용하여 new 구조체 인스턴스를 만들 수도 있지만 다음 예제와 같이 사용할 필요는 없습니다.
using System;
namespace Example
{
public struct Person
{
public string Name;
public int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
public class Application
{
static void Main()
{
// Create struct instance and initialize by using "new".
// Memory is allocated on thread stack.
Person p1 = new("Alex", 9);
Console.WriteLine($"p1 Name = {p1.Name} Age = {p1.Age}");
// Create new struct object. Note that struct can be initialized
// without using "new".
Person p2 = p1;
// Assign values to p2 members.
p2.Name = "Spencer";
p2.Age = 7;
Console.WriteLine($"p2 Name = {p2.Name} Age = {p2.Age}");
// p1 values remain unchanged because p2 is copy.
Console.WriteLine($"p1 Name = {p1.Name} Age = {p1.Age}");
}
}
/*
Output:
p1 Name = Alex Age = 9
p2 Name = Spencer Age = 7
p1 Name = Alex Age = 9
*/
}
스레드 스택은 p1와 p2 모두에 대해 메모리를 할당합니다. 프로그램은 선언하는 형식 또는 메서드와 함께 해당 메모리를 회수합니다. 이 메모리 관리는 할당할 때 구조체가 복사되는 이유 중 하나입니다. 반면 공용 언어 런타임은 개체에 대한 모든 참조가 범위를 벗어날 때 클래스 인스턴스에 할당하는 메모리를 자동으로 회수(가비지 수집)합니다. C++에서처럼 클래스 개체를 결정적으로 삭제할 수 없습니다. .NET의 가비지 수집에 대한 자세한 내용은 가비지 수집참조하세요.
비고
공용 언어 런타임은 관리 힙에서의 메모리 할당 및 할당 해제를 고도로 최적화합니다. 대부분의 경우 스택에서 구조체 인스턴스를 할당하는 것과 힙에서 클래스 인스턴스를 할당하는 성능 비용에는 큰 차이가 없습니다.
객체 동일성 대 값 동등성
두 개체를 같음으로 비교할 때 먼저 두 변수가 메모리에서 동일한 개체를 나타내는지 또는 하나 이상의 필드 값이 같은지 여부를 결정합니다. 값을 비교하려는 경우 개체가 값 형식(구조체) 또는 참조 형식(클래스, 대리자, 배열)의 인스턴스인지를 고려합니다.
정적 Object.ReferenceEquals 메서드를 사용하여 두 클래스 인스턴스가 메모리에서 동일한 위치를 참조하는지 여부를 확인합니다(즉 , ID가 동일함). (System.Object 사용자 정의 구조체 및 클래스를 포함하여 모든 값 형식 및 참조 형식에 대한 암시적 기본 클래스입니다.
기본적으로 메서드는 ValueType.Equals 두 구조체 인스턴스의 인스턴스 필드에 동일한 값이 있는지 여부를 결정합니다. 모든 구조체는 System.ValueType암시적으로 상속되므로 다음 예제와 같이 개체에서 직접 메서드를 호출합니다.
// Person is defined in the previous example. //public struct Person(string name, int age) //{ // public string Name { get; set; } = name; // public int Age { get; set; } = age; //} Person p1 = new("Wallace", 75); Person p2 = new("", 42); p2.Name = "Wallace"; p2.Age = 75; if (p2.Equals(p1)) Console.WriteLine("p2 and p1 have the same values."); // Output: p2 and p1 have the same values.기본 System.ValueType 구현은 경우에 따라
Equals의 박싱 및 리플렉션을 사용합니다. 사용자 형식에 특화된 효율적인 동등성 알고리즘을 제공하는 방법에 대한 자세한 내용은 형식을 레코드로 만들 수 없는 경우 직접 동등성을 구현을(를) 참조하세요. 레코드는 같음을 위해 값 의미 체계를 사용하는 참조 형식입니다.두 클래스 인스턴스의 필드 값이 같은지 여부를 확인하려면 Equals 메서드 또는 == 연산자사용할 수 있습니다. 그러나 클래스가 재정의되거나 오버로드된 경우에만 이를 사용하여 해당 형식의 개체에 대해 "같음"이 무엇을 의미하는지에 대한 사용자 지정 정의를 제공합니다. 클래스는 IEquatable<T> 인터페이스 또는 IEqualityComparer<T> 인터페이스를 구현할 수도 있습니다. 두 인터페이스 모두 값 같음을 테스트하는 데 사용할 수 있는 메서드를 제공합니다. 직접 만든 클래스에서
를 재정의하도록 설계할 때는 형식이 레코드가 될 수 없는 경우 직접 동등성 구현 및 에 명시된 지침을 반드시 따르세요.
관련 섹션
자세한 내용은 다음을 참조하세요:
.NET