C# 공개 게터와 세터와 컬렉션을위한 개인 방법을 만드는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1080644

  •  22-08-2019
  •  | 
  •  

문제

"A"SortedList Collection "SRTDLST"속성이있는 클래스 "A"와이 클래스 내부 "A"A "A"는 "SRTDLST"항목의 추가 또는 뺄셈을 허용하고 싶습니다. 그러나 클래스 "A"의 경우 새 항목을 추가하거나 기존 항목을 빼지 않도록 항목의 내용을 얻거나 설정할 수 있습니다. 코드 :

class A
{
    public SortedList<string, string> SrtdLst = new SortedList<string, string>();

    public A()
    {
        // This must work:
        SrtdLst.Add("KeyA", "ValueA");
        // This too:
        SrtdLst["KeyA"] = "ValueAAA";
    }
}

class B
{
    public A a = new A();
    public B()
    {
        // I want the following code to fail:
        a.SrtdLst.Add("KeyB", "ValueB");
        // But this must work:
        a.SrtdLst["KeyA"] = "ValueBBB";
   }
}

업데이트 : System.data.sqlclient.sqlcommand와 같은 클래스를 만들고 싶습니다. 저장된 절차의 경우 "매개 변수"모음을 채우는 멤버 "deiveParameters"를 사용할 수 있으므로 각 항목의 값 만 수정할 수 있습니다.

이 작업은 어떻게 할 수 있습니까?

도움이 되었습니까?

해결책

컴파일 시간에 수정 작업을 금지하려면 유형 안전 솔루션이 필요합니다.

공개적으로 허용 된 작업에 대한 인터페이스를 선언합니다. 해당 인터페이스를 속성 유형으로 사용하십시오.

public interface IReadOnlyList<T>
{
    T this[int index] { get; }

    int Count { get; }
}

그런 다음 표준 컬렉션 클래스에서 해당 인터페이스를 구현하고 상속하는 클래스를 선언합니다.

public class SafeList<T> : List<T>, IReadOnlyList<T> { }

인터페이스 정의를 올바르게 받고 있다고 가정하면 기본 클래스가 이미 구현을 제공하므로 손으로 아무것도 구현할 필요가 없습니다.

해당 파생 클래스를 속성 값을 저장하는 필드 유형으로 사용하십시오.

public class A
{
    private SafeList<string> _list = new SafeList<string>();

    public IReadOnlyList<string>
    {
        get { return _list; }
    }
}

클래스 A에서 사용할 수 있습니다 _list 직접적으로 내용을 수정하십시오. 클래스 A의 클라이언트는 IReadOnlyList<T>.

예를 들어, 목록 대신 SortedList를 사용하므로 인터페이스는 아마도

public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
    V this[K index] { get; }        
}

나는 그것을 ienumerible에 상속하게 만들었습니다. 안전한 수업은 다음과 같습니다.

public class SafeSortedList<K, V> : SortedList<K, V>, IReadOnlyDictionary<K, V> { }

그러나 그렇지 않으면 그것은 같은 생각입니다.

업데이트 : 방금 (어떤 이유로 든 추측 할 수 없음) 운영 수정을 금지하고 싶지 않다는 것을 알았습니다. 수정 작업을 금지하고 싶습니다. 매우 이상하지만 여전히 같은 솔루션입니다. 허용하고 싶은 작업이 무엇이든 인터페이스에서 "열기":

public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
    V this[K index] { get; set; }        
}

물론, 그것은 지금 인터페이스의 잘못된 이름입니다 ... 왜 지구상에서 추가를 금지하고 싶지만 인덱서를 통해 금지하지 않으시겠습니까? (인덱서는 추가 방법이 할 수있는 것처럼 항목을 추가하는 데 사용될 수 있습니다.)

업데이트

귀하의 의견에서 나는 기존 키/값 쌍의 값에 할당을 허용하고 싶지만 이전에 알려지지 않은 키에 할당을 허용하지 않는다는 것을 의미합니다. 분명히 런타임에 문자열에 의해 키를 지정할 때, 컴파일 타임에 그것을 잡을 수있는 방법은 없습니다. 따라서 런타임 확인을 위해 갈 수도 있습니다.

public class FixedSizeDictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
{
    IDictionary<TKey, TValue> _realDictionary;

    public FixedSizeDictionaryWrapper(IDictionary<TKey, TValue> realDictionary)
    {
        _realDictionary = realDictionary;
    }

    public TValue this[TKey key]
    {
        get { return _realDictionary[key]; }

        set 
        {
            if (!_realDictionary.Contains(key))
                throw new InvalidOperationException();

            _realDictionary[key] = value;
        }
    }

    // Implement Add so it always throws InvalidOperationException

    // implement all other dictionary methods to forward onto _realDictionary
}

평범한 사전이 있고 기존 값을 업데이트하는 것을 신뢰하지 않는 방법으로 건네주고 싶을 때 마다이 중 하나에 마무리하십시오.

다른 팁

편집 : 원본 답변은 다음과 같습니다. Earwicker가 지적했듯이, 나는 당신이 그렇지 않습니다 그것을 예방하기 위해 그것을 읽기 위해 그것을 요구합니다. Add 작업. 그것은 나에게 좋은 생각처럼 들리지 않습니다. Add 그리고 인덱서 세터는 그게됩니다 Add 요소가 이미 존재하는 경우 예외를 던집니다. 어쨌든 발신자가 쉽게 가짜를 만들 수 있습니다.

왜 하나의 작업 만 제한하고 싶습니까?


원래 답변

우선, 공공 분야를 사용하지 마십시오. 그것은 문제를 해결하는 확실한 방법입니다.

임의의 라운드에서 읽기 전용 래퍼 클래스를 원하는 것 같습니다. IDictionary. 그런 다음 클래스 내에서 개인 변수에 액세스하는 동안 포장지를 반환하는 공공 재산을 가질 수 있습니다. 예를 들어:

class A
{
    private SortedList<string, string> sortedList = new SortedList<string, string>();

    public IDictionary<string, string> SortedList 
    {
        get { return new ReadOnlyDictionaryWrapper(sortedList);
    }

    public A()
    {
        sortedList.Add("KeyA", "ValueA");
        sortedList["KeyA"] = "ValueAAA";
    }
}

이제 당신은 방금 찾아야합니다 ReadOnlyDictionary 구현 ... 지금 당장 구현할 수는 없지만 필요한 경우 나중에 돌아올 것입니다 ...

목록을 비공개로 만들고 인덱서로 노출하십시오.

class A {

   private SortedList<string, string> _list;

   public A() {
      _list = new SortedList<string, string>()
   }

   public string this[string key] {
      get {
         return _list[key];
      }
      set {
         _list[key] = value;
      }
   }

}

이제 색인을 사용하여 항목에만 액세스 할 수 있습니다.

a["KeyA"] = "ValueBBB";

그러나 목록의 인덱서를 사용하면 새 항목을 생성 할 수 있으므로 원하지 않는 경우 인덱서에 코드를 추가해야합니다.

키가 클래스 외부에서 알려져 있다면 래퍼 클래스에 ChangeItem (key, newValue) 및 readItem (키)을 추가 할 수 있습니다. 그런 다음 SortedList를 수업에 비공개로 유지하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top