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; }

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

public event Action OnChange = delegate {};

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


0

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


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