c# - 필드란 - 필드와 속성의 차이점은 무엇입니까?




프로퍼티 와 필드 (20)

차이점 - 사용시기 (언제, 왜)

필드 는 클래스 또는 구조체에서 직접 선언 된 변수입니다. 클래스 나 구조체는 인스턴스 필드 나 정적 필드 또는 둘 다를 가질 수 있습니다. 일반적으로 액세스가 비공개 또는 보호 된 변수에만 필드를 사용해야합니다. 클래스가 클라이언트 코드에 노출하는 데이터는 메서드, 속성 및 인덱서를 통해 제공되어야합니다 . 내부 필드에 대한 간접 액세스를 위해 이러한 구조를 사용하여 유효하지 않은 입력 값을 방지 할 수 있습니다.

속성 은 개인 필드 값을 읽거나 쓰거나 계산할 수있는 유연한 메커니즘을 제공하는 멤버입니다. 속성은 공용 데이터 멤버 인 것처럼 사용할 수 있지만 실제로는 접근 자라고하는 특수 메서드입니다. 이를 통해 데이터에 쉽게 액세스 할 수 있으며 여전히 방법안전성과 유연성을 향상 시키는 데 도움이됩니다. 속성을 사용하면 구현 또는 인증 코드를 숨기고 클래스에서 값을 가져 와서 설정하는 공개 방법을 노출 할 수 있습니다. get 속성 접근자는 속성 값을 반환하는 데 사용되고 set 접근자는 새 값을 할당하는 데 사용됩니다.

C #에서는 필드가 속성과 다른 점이 무엇이며 속성 대신 필드를 사용해야하는시기는 언제입니까?


(이것은 정말로 코멘트 일 것이지만, 코멘트를 게시 할 수 없기 때문에, 게시물로서 적절하지 않은 경우는 용서해주십시오).

예전에 필자는 권장 사례가 동일한 속성의 def가 필드에 액세스했을 때 속성 대신 public 필드를 사용하는 곳에서 작업했습니다.

get { return _afield; }
set { _afield = value; }

그들의 추론은 필요한 경우 공공 장이 나중에 나중에 재산으로 전환 될 수 있다는 것이 었습니다. 그 당시에는 조금 이상해 보였습니다. 이 게시물들로 판단하면 많은 사람들이 동의하지 않는 것처럼 보입니다. 사물을 바꾸려고하면 뭐라고했을까요?

편집 : 나는이 장소의 모든 코드 기반이 동시에 컴파일 되었기 때문에 공용 필드를 속성으로 변경하여 클래스의 공용 인터페이스를 변경하는 것이 문제가 아니라고 생각할 수도 있다고 덧붙여 야합니다.



Wikipedia에서 - 객체 지향 프로그래밍 :

OOP (Object-Oriented Programming)는 "객체"개념을 기반으로하는 프로그래밍 패러다임으로 데이터라는 속성 을 필드 형식으로 포함하는 데이터 구조입니다. 및 코드를 절차의 형태로, 종종 방법이라고합니다 . (강조가 추가됨)

속성은 실제로 객체의 비헤이비어 중 일부이지만 객체의 소비자가 객체의 데이터로 작업한다는 환영 / 추상화를 제공하도록 설계되었습니다.


객체 지향 프로그래밍 원리에 따르면 클래스의 내부 동작은 외부 세계로부터 숨겨져 있어야합니다. 필드를 노출하면 본질적으로 클래스의 내부 구현을 노출하게됩니다. 따라서 Properties (또는 Java의 경우 메서드)로 필드를 래핑하여 우리에 따라 코드를 위반하지 않고 구현을 변경할 수 있습니다. 속성에 논리를 넣을 수있는 것을 보는 것만으로도 우리가 필요하다면 검증 논리 등을 수행 할 수 있습니다. C # 3은 자동 생성 기능을 혼란스럽게합니다. 이것은 단순히 Property를 정의 할 수있게 해주 며, C # 3 컴파일러는 private 필드를 생성합니다.

public class Person
{
   private string _name;

   public string Name
   {
      get
      {
         return _name;
      }
      set
      {
         _name = value;
      }
   }
   public int Age{get;set;} //AutoProperty generates private field for us
}

기술적으로, 속성 차이는 사용자가 만든 필드 주위의 래퍼이거나 컴파일러에 의해 자동으로 만들어지기 때문에 기술적으로는 생각하지 않습니다. 속성의 목적은 캡슐화를 적용하고 간단한 메서드와 유사한 기능을 제공하는 것입니다. 필드를 공개로 선언하는 것은 나쁜 습관 일 뿐이지 만 문제는 없습니다.


당신이 "차"인 수업을 가지고있을 때. 특성은 색깔, 모양이다.

필드는 클래스의 범위 내에서 정의 된 변수입니다.


두 번째 질문은 "언제 부동산 대신 필드를 사용해야합니까?"라는 질문에이 간단한 답변 만 간략하게 설명되어 있습니다.

일반적으로 다른 모든 대답은 좋은 디자인에 관한 사항입니다. 노출 필드보다 속성을 노출하는 것이 좋습니다. 당신이 아마 규칙적으로 스스로를 발견하지는 않지만, "와우, 재산 대신에 이것을 밭 으로 만들면 얼마나 더 나쁜 것이 될지 상상해보십시오."라고 말하는 상황을 생각하는 것이 훨씬 더 희귀합니다. 와우, 하나님 께 재산 대신 여기에 들판을 사용하여 주셔서 감사합니다. "

그러나 필드가 속성을 넘는 장점 중 하나는 "ref"/ "out"매개 변수로 사용할 수있는 능력입니다. 다음과 같은 서명을 가진 메소드가 있다고 가정 해보십시오.

public void TransformPoint(ref double x, ref double y);

이 메서드를 사용하여 다음과 같이 만든 배열을 변형하려고한다고 가정합니다.

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

XY 는 속성이기 때문에 여기서는 가장 빠른 방법이라고 생각합니다.

for (int i = 0; i < points.Length; i++)
{
    double x = points[i].X;
    double y = points[i].Y;
    TransformPoint(ref x, ref y);
    points[i].X = x;
    points[i].Y = y;
}

그리고 그것은 꽤 좋을 것입니다! 그렇지 않으면 측정 할 수있는 측정법이 없으면 냄새를 맡길 이유가 없습니다. 그러나 기술적으로는 이렇게 빠른 것은 보장되지 않습니다.

internal struct MyPoint
{
    internal double X;
    internal double Y;
}

// ...

MyPoint[] points = new MyPoint[1000000];
Initialize(points);

// ...

for (int i = 0; i < points.Length; i++)
{
    TransformPoint(ref points[i].X, ref points[i].Y);
}

몇 가지 measurements 직접 수행하면 필드가있는 버전은 속성이있는 버전 (.NET 4.6, Windows 7, x64, 릴리스 모드, 디버거가 연결되지 않음)으로 약 61 %의 시간이 소요됩니다. TransformPoint 메서드의 비용이 높을수록 그 차이가 덜 두드러집니다. 이 과정을 반복하려면 주석 처리되지 않은 첫 번째 줄을 주석 처리하여 실행하십시오.

위의 경우 성능상의 이점이 없더라도 Interlocked 또는 Volatile 계열의 메소드를 호출 할 때와 같이 ref 및 out 매개 변수를 사용할 수있는 것이 유익 할 수있는 다른 장소가 있습니다. 참고 : 이것이 새로운 경우에, 휘발성은 기본적으로 volatile 키워드에 의해 제공된 동일한 행동을 취하는 방법입니다. volatile 처럼, 이름에서 알 수 있듯이 모든 스레드 안전 문제를 마술처럼 해결하지는 않습니다.

나는 분명히 당신이 "오, 나는 속성 대신 필드를 노출해야한다고 주장하는 것처럼 보이고 싶지 않습니다." 요점은 "ref"또는 "out"매개 변수를 사용하는 호출에서 이러한 멤버를 정기적으로 사용해야하는 경우, 특히 속성의 부가 가치 요소 중 일부를 필요로하지 않는 단순한 값 유형 인 경우, 의논 할 수있다.


많은 사람들이 PropertiesField 의 기술적 장단점에 대해 설명했기 때문에 실시간 예제를 얻을 때입니다.

1. 속성을 사용하면 읽기 전용 액세스 수준을 설정할 수 있습니다

dataTable.Rows.CountdataTable.Columns[i].Caption 의 경우를 생각해보십시오. 그들은 DataTable 클래스에서 왔으며 둘 다 우리에게 공개되어 있습니다. 액세스 수준의 차이는 dataTable.Rows.Count 값을 설정할 수는 없지만 dataTable.Columns[i].Caption 을 읽고 쓸 수 dataTable.Columns[i].Caption 입니다. Field 통해 가능합니까? 아니!!! 이 작업은 Properties 만 수행 할 수 있습니다.

public class DataTable
{
    public class Rows
    {       
       private string _count;        

       // This Count will be accessable to us but have used only "get" ie, readonly
       public int Count
       {
           get
           {
              return _count;
           }       
       }
    } 

    public class Columns
    {
        private string _caption;        

        // Used both "get" and "set" ie, readable and writable
        public string Caption
        {
           get
           {
              return _caption;
           }
           set
           {
              _caption = value;
           }
       }       
    } 
}

2. PropertyGrid의 속성

Visual Studio에서 Button 으로 작업했을 수도 있습니다. 속성은 Text , Name 등과 같이 PropertyGrid 표시됩니다. 버튼을 드래그 앤 드롭하면 속성을 클릭하면 Button 클래스가 자동으로 찾아지고 Properties 필터링되어 PropertyGrid 표시됩니다 (여기서 PropertyGrid 는 표시되지 않음). Field 는 공개 되더라도).

public class Button
{
    private string _text;        
    private string _name;
    private string _someProperty;

    public string Text
    {
        get
        {
           return _text;
        }
        set
        {
           _text = value;
        }
   } 

   public string Name
   {
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   } 

   [Browsable(false)]
   public string SomeProperty
   {
        get
        {
           return _someProperty;
        }
        set
        {
           _someProperty= value;
        }
   } 

PropertyGrid 에서 NameText 속성이 표시되지만 SomeProperty 는 표시되지 않습니다. 왜??? 속성은 특성을 받아 들일 수 있기 때문입니다. [Browsable(false)] 가 false 인 경우에는 표시되지 않습니다.

3. 속성 내에서 문장을 실행할 수 있습니다.

public class Rows
{       
    private string _count;        


    public int Count
    {
        get
        {
           return CalculateNoOfRows();
        }  
    } 

    public int CalculateNoOfRows()
    {
         // Calculation here and finally set the value to _count
         return _count;
    }
}

4. Binding Source에서 Properties 만 사용할 수 있습니다.

바인딩 소스 는 코드 줄 수를 줄이는 데 도움이됩니다. FieldsBindingSource 허용하지 않습니다. 우리는 Properties 를 사용해야합니다.

5. 디버깅 모드

Field 를 사용하여 값을 보유한다고 가정 해보십시오. 어느 시점에서 우리는 디버그하고 값이 해당 필드에 대해 null이되는 곳을 확인해야합니다. 이러한 상황에서 우리는 Property 를 사용할 수 있으며 Property 내에서 디버그 모드를 설정할 수 있습니다.

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }

백그라운드에서 속성은 메서드로 컴파일됩니다. 따라서 Name 속성은 get_Name()set_Name(string value) 으로 컴파일됩니다. 컴파일 된 코드를 연구하면이 사실을 알 수 있습니다. 따라서 사용시 매우 적은 성능 오버 헤드가 있습니다. 일반적으로 필드를 외부에 노출하는 경우 항상 속성을 사용하며, 값의 유효성 검사를 수행해야하는 경우 내부적으로 사용합니다.


속성은 비대칭 액세스를 지원합니다. 즉, getter와 setter 중 하나 또는 둘 중 하나만 가질 수 있습니다. 마찬가지로 속성은 getter / setter에 대한 개별 액세스 가능성을 지원합니다. 필드는 항상 대칭입니다. 즉, 항상 값을 가져오고 설정할 수 있습니다. 이것에 대한 예외는 초기화 후에 분명히 설정할 수없는 읽기 전용 필드입니다.

속성은 매우 오랫동안 실행될 수 있으며 부작용이 있으며 예외를 throw 할 수도 있습니다. 필드는 부작용없이 빠르며 예외를 throw하지 않습니다. 부작용으로 인해 속성은 각 호출마다 다른 값을 반환 할 수 있습니다 (DateTime.Now의 경우처럼 DateTime.Now가 항상 DateTime.Now와 같지 않음). 필드는 항상 같은 값을 반환합니다.

필드는 out / ref 매개 변수에 사용될 수 있지만 속성은 그렇지 않을 수 있습니다. 프로퍼티는 추가적인 로직을 지원합니다 - 이것은 다른 것들 사이에 느슨한 로딩을 구현하는 데 사용될 수 있습니다.

속성은 값을 가져 오거나 설정하는 것을 의미하는 것을 캡슐화함으로써 추상화 수준을 지원합니다.

대부분의 / 모든 경우에 속성을 사용하지만 부작용을 피하십시오.


속성은 특별한 종류의 클래스 멤버입니다. 속성에서 미리 정의 된 Set 또는 Get 메서드를 사용합니다. 이들은 private 필드의 값을 읽고 쓰거나 변경할 수있는 접근자를 사용합니다.

예를 들어, name, age 및 Employee_Id에 대해 private 필드가있는 Employee 라는 클래스를 사용합니다. 우리는 수업 외에서는이 필드에 액세스 할 수 없지만 속성을 통해 이러한 개인 필드에 액세스 할 수 있습니다.

왜 우리는 속성을 사용합니까?

클래스 필드를 public으로 설정하고 노출하는 것은 위험합니다. 할당 된 항목과 반환되는 항목을 제어 할 수는 없으므로 위험합니다.

예를 들어이를 분명히 이해하려면 ID, 패스 마크, 이름을 가진 학생 수업을들 수 있습니다. 이제이 예제에서 공개 필드의 일부 문제

  • ID는 -ve가 아니어야합니다.
  • 이름을 null로 설정할 수 없습니다.
  • 통과 표시는 읽기 전용이어야합니다.
  • 학생 이름이 누락 된 경우 이름을 반환하지 않아야합니다.

이 문제를 제거하려면 Get 및 set 메서드를 사용합니다.

// A simple example
public class student
{
    public int ID;
    public int passmark;
    public string name;
}

public class Program
{
    public static void Main(string[] args)
    {
       student s1 = new student();
       s1.ID = -101; // here ID can't be -ve
       s1.Name = null ; // here Name can't be null
    }
}

이제 우리는 get과 set 메소드의 예제를 취한다.

public class student
{
    private int _ID;
    private int _passmark;
    private string_name ;
    // for id property
    public void SetID(int ID)
    {
        if(ID<=0)
        {
            throw new exception("student ID should be greater then 0");
        }
        this._ID = ID;
    }
    public int getID()
    {
        return_ID;
    }
}
public class programme
{
    public static void main()
    {
        student s1 = new student ();
        s1.SetID(101);
    }
    // Like this we also can use for Name property
    public void SetName(string Name)
    {
        if(string.IsNullOrEmpty(Name))
        {
            throw new exeception("name can not be null");
        }
        this._Name = Name;
    }
    public string GetName()
    {
        if( string.IsNullOrEmpty(This.Name))
        {
            return "No Name";
        }
        else
        {
            return this._name;
        }
    }
        // Like this we also can use for Passmark property
    public int Getpassmark()
    {
        return this._passmark;
    }
}

속성을 사용하면 속성 값이 변경되거나 (예 : PropertyChangedEvent) 이벤트가 취소되거나 취소하기 위해 값이 변경되기 전에 이벤트를 발생시킬 수 있습니다.

필드에 대한 직접 액세스는 불가능합니다.

public class Person {
 private string _name;

 public event EventHandler NameChanging;     
 public event EventHandler NameChanged;

 public string Name{
  get
  {
     return _name;
  }
  set
  {
     OnNameChanging();
     _name = value;
     OnNameChanged();
  }
 }

 private void OnNameChanging(){
   EventHandler localEvent = NameChanging;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }

 private void OnNameChanged(){
   EventHandler localEvent = NameChanged;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }
}

속성이 필드를 노출합니다. 필드는 (거의 항상) 클래스에 대해 비공개로 유지되어야하고 get 및 set 속성을 통해 액세스되어야합니다. 속성은 클래스를 사용하는 것들로 액세스되는 외부 방식에 영향을 미치지 않으면 서 필드를 변경할 수있는 수준의 추상화를 제공합니다.

public class MyClass
{
    // this is a field.  It is private to your class and stores the actual data.
    private string _myField;

    // this is a property. When accessed it uses the underlying field,
    // but only exposes the contract, which will not be affected by the underlying field
    public string MyProperty
    {
        get
        {
            return _myField;
        }
        set
        {
            _myField = value;
        }
    }

    // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
    // used to generate a private field for you
    public int AnotherProperty{get;set;} 
}

@Kent는 필드가 필드를 캡슐화 할 필요가 없으며 다른 필드에서 계산을 수행하거나 다른 용도로 사용할 수 있다고 지적합니다.

@GSS는 속성에 액세스 할 때 유효성 검사, 또 다른 유용한 기능과 같은 다른 논리를 수행 할 수 있다고 지적합니다.


전통적으로 비공개 필드는 getter 및 setter 메서드를 통해 설정됩니다. 적은 코드를 위해 속성을 사용하여 필드를 설정할 수 있습니다.


중요한 차이점은 인터페이스에는 속성이 있지만 필드는 가질 수 없다는 것입니다. 클래스의 공용 인터페이스를 정의하는 데 속성을 사용해야하는 반면 클래스의 내부적 인 내부 작업에는 필드를 사용하도록되어 있다는 것을 강조합니다. 원칙적으로 나는 공개 필드를 거의 만들지 않으며 마찬가지로 비공개 속성도 거의 만들지 않습니다.


필드의 디자인은 필드가 부모 클래스, 즉 클래스에 의해서만 수정 될 필요가 있다는 것입니다. 결과 변수가 비공개가 된 다음 외부 클래스 / 메소드를 읽을 수있는 권한을 부여 할 수 있도록 Get 만 사용하여 속성 시스템을 통과합니다. 필드는 속성과 읽기 전용으로 검색됩니다! 이를 수정하려면 메소드 (예 : 생성자)를 거쳐야하며 보안을 유지할 수있는 방법 덕분에 "플랜지 (flange)"를 사용하기 때문에 코드를 더 잘 제어 할 수 있습니다.누구나 모든 것을 공개 할 수 있기 때문에 모든 가능한 경우, 변수 / 메소드 / 클래스 등의 개념은 제 의견으로는 코드의 개발, 유지 관리에 도움이됩니다. 예를 들어 공개 필드가있는 코드를 다시 시작하면 목표와 관련하여 아무 것도 할 수 없으므로 코드가 작성된 이유에 대한 논리가됩니다. 그것은 내 견해입니다.

내가 고전적인 모델의 개인 필드 / 공개 읽기 전용 속성을 사용할 때 10 개의 private 필드에 10 개의 public 속성을 작성해야합니다! 이 코드는 정말 빨라질 수 있습니다. 개인 설정 도구를 발견하고 이제는 개인 설정 도구로 공용 속성 만 사용합니다. 설정자는 백그라운드에서 개인 필드를 만듭니다.

왜 내 고전적인 프로그래밍 스타일은 다음과 같았습니다 :

public class MyClass
{
 private int _id;
 public int ID { get { return _id; } }
 public MyClass(int id)
 {
  _id = id;
 }
}

새로운 프로그래밍 스타일 :

public class MyClass
{
 public int ID { get; private set; }
 public MyClass(int id)
 {
  ID = id;
 }
}

그것에 대해 생각하십시오 :이 방에 들어가기위한 방과 문이 있습니다. 누가 들어오는 지 확인하고 방을 확보하려면 속성을 사용해야합니다. 그렇지 않으면 문을 열지 않으며 모든 규칙을 따르지 않아도됩니다.

class Room {
   public string sectionOne;
   public string sectionTwo;
}

Room r = new Room();
r.sectionOne = "enter";

사람들이 sectionOne에 쉽게 들어가고 있습니다. 검사가 없습니다.

class Room 
{
   private string sectionOne;
   private string sectionTwo;

   public string SectionOne 
   {
      get 
      {
        return sectionOne; 
      }
      set 
      { 
        sectionOne = Check(value); 
      }
   }
}

Room r = new Room();
r.SectionOne = "enter";

이제 그 사람을 확인하고 그 사람이 그와 악한 것을 가지고 있는지 알아 봅니다.


속성은 필드를 표시하는 데 사용됩니다. 그들은 private 필드의 값을 읽고, 쓰거나 조작 할 수있는 접근 자 (set, get)를 사용합니다.

속성은 저장 위치의 이름을 지정하지 않습니다. 대신 값을 읽거나 쓰거나 계산하는 접근자를가집니다.

속성을 사용하여 필드에 설정된 데이터 유형에 대한 유효성을 설정할 수 있습니다.

예를 들어 나이가 음수가 될 수 없으므로 양수 값을 허용해야한다는 민간 정수 필드 나이가 있습니다.

getter와 setter를 사용하고 속성을 사용하여 두 가지 방법으로이 작업을 수행 할 수 있습니다.

 Using Getter and Setter

    // field
    private int _age;

    // setter
    public void set(int age){
      if (age <=0)
       throw new Exception();

      this._age = age;
    }

    // getter
    public int get (){
      return this._age;
    }

 Now using property we can do the same thing. In the value is a key word

    private int _age;

    public int Age{
    get{
        return this._age;
    }

    set{
       if (value <= 0)
         throw new Exception()
       }
    }

자동 구현 된 속성을 얻고 설정하는 논리가 없으면 자동 구현 된 속성을 사용할 수 있습니다.

U 때 자체 자동 구현 속성은 컴파일 개인, 익명의 필드 생성 에만 get 및 set 접근을 통해 액세스 할 수 있습니다.

public int Age{get;set;}

추상 속성 추상 클래스는 파생 클래스에서 구현되어야하는 추상 속성을 가질 수 있습니다

public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }

// overriden something like this
// Declare a Name property of type string:
  public override string Name
  {
     get
     {
        return name;
     }
     set
     {
        name = value;
     }
  }

개인적으로 속성을 설정할 수 있습니다.이 속성에서 우리는 개인 속성으로 클래스를 설정할 수 있습니다.

public int MyProperty
{
    get; private set;
}

이 코드로도 같은 결과를 얻을 수 있습니다. 필드에 직접 값을 설정해야하므로이 속성 집합 기능을 사용할 수 없습니다.

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

추가 정보 : 기본적으로 get 및 set 접근자는 속성 자체만큼 액세스 가능합니다. 보다 제한적인 액세스 수정자를 적용하여 접근 자 액세스 가능성을 개별적으로 제어하고 제한 할 수 있습니다 (get 및 set).

예:

public string Name
{
    get
    {
        return name;
    }
    protected set
    {
        name = value;
    }
}

여기서 get은 공개적으로 액세스되지만 (속성은 public이므로) set이 보호됩니다 (보다 제한된 액세스 지정자).







field