C # 3.0 이상에서 속성과 필드의 차이점


140

C #에서 필드와 속성의 차이점 은 무엇입니까? 그러나 내 질문은 (내 관점에서) 약간의 차이가 있습니다.

내가 알면

  • 나는 "속성에서만 작동하는 기술"과 함께 수업을 사용하지 않을 것이며
  • getter / setter에서 유효성 검사 코드를 사용하지 않습니다.

속성 설정의 일부 유형의 제어와 같은 차이점 (스타일 / 미래 개발 항목 제외)이 있습니까?

다음과 같은 추가 차이점이 있습니까?

public string MyString { get; set; }

과

public string myString;

(첫 번째 버전에는 C # 3.0 이상이 필요하며 컴파일러는 개인 필드를 생성한다는 것을 알고 있습니다.)


답변:


117

캡슐화.

두 번째 인스턴스에서는 방금 변수를 정의했으며 첫 번째에는 변수 주위에 getter / setter가 있습니다. 따라서 나중에 변수의 유효성을 검사하기로 결정하면 훨씬 쉬워집니다.

또한 Intellisense에서는 다르게 표시됩니다. :)

편집 : OP 업데이트 업데이트 질문-다른 제안을 무시하려면 다른 이유는 단순히 OO 디자인이 좋지 않기 때문입니다. 그리고 그럴만 한 이유가 없다면 항상 공개 변수 / 필드보다 속성을 선택하십시오.


9
왜 더 쉬울까요? 필드를 속성으로 바꾸고 개인 백업 필드를 추가하지 못하게하는 이유 이것이 호출 코드에 어떤 영향을 줍니까?
— Serge Wautier

30
@Serge-이미 컴파일 된 코드에 영향을줍니다. 예를 들어 여러 응용 프로그램에서 사용하는 라이브러리를 개발하는 경우 필드를 해당 라이브러리의 속성으로 변경하려면 각 응용 프로그램을 다시 컴파일해야합니다. 속성 인 경우 걱정하지 않고 속성을 업데이트 할 수 있습니다.
— 더스틴 캠벨

나는 당신에게 전적으로 동의합니다, 나는 항상 속성을 사용합니다. 나는 가능한 차이에 대해 궁금했다
— p4bl0 03-17-09

24
소비되는 코드가 영향을받는 클래스와 동시에 동시에 재 컴파일되는 경우 (내부적으로 보이지 않는 개인 또는 내부의 모든 것이 100 % 안전함) 필드를 완벽하게 만드는 것이
— 좋습니다

1
와우 Shuggy 당신의 의견은 내가 찾던 정답입니다!
— p4bl0

160

필드와 속성은 동일하게 보이지만 다릅니다. 속성은 메서드이므로 속성에 지원되지 않는 특정 사항 및 속성에는 발생할 수 있지만 필드의 경우에는 전혀 발생하지 않는 사항이 있습니다.

차이점 목록은 다음과 같습니다.

  • 필드는 out/ref인수의 입력으로 사용할 수 있습니다 . 속성은 할 수 없습니다.
  • 필드는 여러 번 호출 될 때 항상 동일한 결과를 생성합니다 (여러 스레드에 대한 문제를 생략 한 경우). 과 같은 속성 DateTime.Now이 항상 자신과 같지는 않습니다.
  • 속성은 예외를 던질 수 있습니다-필드는 절대 그렇게하지 않습니다.
  • 속성에 부작용이 있거나 실행하는 데 시간이 오래 걸릴 수 있습니다. 필드는 부작용이 없으며 주어진 유형에 대해 항상 예상되는 것보다 빠릅니다.
  • 속성은 getter / setters에 대해 서로 다른 접근성을 지원합니다. 필드는 지원하지 않습니다 (그러나 필드를 만들 수는 있음 readonly).
  • 리플렉션을 사용할 때 속성과 필드는 다르게 취급되어 다르게 MemberTypes위치합니다 ( 예 : GetFieldsvs GetProperties)
  • JIT 컴파일러는 필드 액세스와 비교하여 속성 액세스를 매우 다르게 처리 할 수 ​​있습니다. 그러나 동일한 네이티브 코드로 컴파일 할 수는 있지만 차이의 범위가 있습니다.

11
이러한 점 몇 가지를해야하지만주의 하지 모범 사례를 적용하는 경우 차이가. 즉, 속성에는 실제로 부작용이 없어야하며 실행하는 데 시간이 오래 걸리지 않아야합니다.
— Noldorin

15
@Noldorin : 나는 동의하지만 불행히도 해야이 키워드는 여기에있다. 필드가 있으면 동작이 보장됩니다. 필자가 필드를 사용해야한다고 말하지는 않지만 의미상의 차이점을 알고 있어야합니다.
— Brian Rasmussen

4
예, 충분합니다. 초보자 프로그래머는 불행히도 종종 이런 것들에 대한 단서가 없습니다.
— Noldorin

2
또한 필드에는 필드 이니셜 라이저가있을 수 있지만 생성자에서 속성을 초기화해야합니다.
— Dio F

3
이 답변이 허용되는 답변보다 훨씬 우수하다고 생각합니다. 필드보다 속성을 항상 선호하는 "허용 가능한"방법은 나쁜 생각이라고 생각하기 시작했습니다. 데이터 만 처리해야하는 경우 필드를 사용하십시오. 데이터에 기능을 적용해야하는 경우 방법을 사용하십시오. 속성은 알지 못하는 부작용이있을 수 있으므로 (특히 라이브러리를 디자인하지 않고 문서가 거의없는 경우) 대부분의 경우 나에게 반 직관적 인 것처럼 보입니다.
— David Peterson

41

몇 가지 빠르고 명백한 차이점

  1. 속성에는 접근 자 키워드가있을 수 있습니다.

    public string MyString { get; private set; }
  2. 하위 항목에서 속성을 재정의 할 수 있습니다.

    public virtual string MyString { get; protected set; }

1
mmh .. 번호 2 재미있다 .. 나는 그것을 생각하지 않았다
— p4bl0

14

근본적인 차이점은 필드는 지정된 유형의 데이터가 저장되는 메모리의 위치입니다. 특성은 지정된 유형의 값을 검색하거나 설정하기 위해 실행되는 하나 또는 두 개의 코드 단위를 나타냅니다. 이러한 접근 자 메서드의 사용은 필드처럼 동작하는 것처럼 보이는 멤버 (할당 작업의 양쪽에 나타날 수 있음)를 사용하여 구문 적으로 숨겨집니다.


11

접근자는 필드 이상입니다. 다른 사람들은 이미 몇 가지 중요한 차이점을 지적했으며 하나 더 추가 할 것입니다.

속성은 인터페이스 클래스에 참여합니다. 예를 들면 다음과 같습니다.

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

이 인터페이스는 여러 가지 방법으로 만족 될 수 있습니다. 예를 들면 다음과 같습니다.

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

이 구현에서 우리는 Person클래스가 유효하지 않은 상태가되는 것과 호출자가 할당되지 않은 속성에서 null을 얻는 것을 막고 있습니다.

그러나 디자인을 더욱 발전시킬 수있었습니다. 예를 들어, 인터페이스가 setter를 처리하지 않을 수 있습니다. IPerson인터페이스 소비자 는 속성을 설정하는 것이 아니라 속성을 얻는 데에만 관심이 있다고 말하는 것은 합법적입니다 .

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

Person클래스 의 이전 구현은 이 인터페이스를 충족시킵니다. 호출자가 속성을 설정할 수 있다는 사실은 소비자 (소비자)의 관점에서 의미가 없습니다 IPerson. 구체적인 구현의 추가 기능은 예를 들어 빌더에 의해 고려됩니다.

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

이 코드에서 소비자는 부동산 세터에 대해 알지 못합니다. 자신의 사업이 아닙니다. 소비자는 게터 만 필요하며 인터페이스, 즉 계약에서 게터를 얻습니다.

완전히 유효한 또 다른 구현은 IPerson불변 인 개인 클래스와 해당 개인 팩토리입니다.

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

이 코드에서 샘플 소비자는 다시 한 번 속성을 채울 지식이 없습니다. 소비자는 게터와 구체적인 구현 (이름이 비어있는 경우 테스트와 같은 배후의 비즈니스 논리) 만 처리하며 특수 클래스 (빌더 및 공장)에 맡겨집니다. 이러한 모든 작업은 필드에서 완전히 불가능합니다.


7

첫번째:

public string MyString {get; set; }

속성입니다; 두 번째 ( public string MyString)는 필드를 나타냅니다.

차이점은 특정 기술 (인스턴스에 대한 ASP.NET 데이터 바인딩)은 속성이 아닌 필드에서만 작동한다는 것입니다. XML 직렬화의 경우에도 마찬가지입니다. 속성 만 직렬화되고 필드는 직렬화되지 않습니다.


8
잘못된. XML 직렬화 공용 필드를 직렬화합니다.
— Serge Wautier

2
아마도. 그러나 클래스에서 객체 데이터 소스를 만들 때는 필드가 아닌 속성 만 사용해야합니다. (내가 잘못한 것이 아닌 한 : P)
— Svish

좋은 건 DRY;)이지만 다시 한 번 쓰면 C # 언어의 강력한 속성 역할을 좋아합니다. Java에서보다 훨씬 더 잘 구현됩니다 (결과적으로 처음부터) 많은 .net 솔루션이 속성에서만 작동합니다. WPF, ASPX 등
— Jacek Cz

3

대부분의 경우 속성과 필드는 비슷해 보이지만 그렇지 않습니다. 필드에 존재하지 않는 속성에는 제한이 있으며 그 반대도 마찬가지입니다.

다른 사람들이 언급했듯이. 접근자를 비공개로 설정하여 속성을 읽기 전용 또는 쓰기 전용으로 만들 수 있습니다. 필드로는 그렇게 할 수 없습니다. 필드는 불가능하지만 속성은 가상 일 수도 있습니다.

속성을 getXXX () / setXXX () 함수의 구문 설탕으로 생각하십시오. 이것이 그들이 무대 뒤에서 어떻게 구현되는지입니다.


1

필드와 속성 간에는 또 다른 중요한 차이점이 있습니다.

WPF를 사용하는 경우 공용 속성에만 바인딩 할 수 있습니다. 공개 필드에 바인딩하면 작동 하지 않습니다 . INotifyPropertyChanged항상 구현 해야하지만 구현하지 않는 경우에도 마찬가지 입니다.


좋은 건 DRY;)하지만 다시 한 번 쓰면 C # 언어의 강력한 속성 역할을 좋아합니다. Java에서보다 훨씬 더 잘 구현됩니다 (결과적으로 처음부터) 많은 .net 솔루션이 속성에서만 작동합니다. WPF, ASPX 등
— Jacek Cz

1

다른 답변과 예제 중에서도이 예제는 일부 상황에서 유용하다고 생각합니다.

예를 들어 다음과 같이 말하십시오 .OnChange property

public Action OnChange { get; set; }

대리자를 사용하려면 다음 OnChange과 field같이 대리자를 변경해야합니다 .

public event Action OnChange = delegate {};

그러한 상황에서 우리는 원치 않는 접근이나 수정으로부터 우리의 분야를 보호합니다.


0

공용 필드의 필드 대신 항상 속성을 사용해야합니다. 이렇게하면 라이브러리에서 기존 코드를 손상시키지 않고 필요한 경우 나중에 필드에 대한 캡슐화를 구현할 수 있습니다. 라이브러리를 사용하는 종속 모듈도 다시 빌드해야합니다.


"항상"은 어려운 단어를 다루는 단어입니다. C #에서 (Java보다 나은) 속성은 강력한 위치를 가지며 ASP, WPF 및 기타에서 "바인딩"의 주요 / 방법입니다 (아마도 예외는 없습니다). 그럼에도 불구하고 나는 필드가없는 디자인이 의미가 없다고 상상할 수있다. (때로는)
— Jacek Cz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.