[英]C# How to make public getters and setters and private methods for a collection?
我想要一個帶有(例如)SortedList集合“SrtdLst”屬性的類“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。 對於存儲過程,您可以使用填充“參數”集合的成員“DeriveParameters”,因此只能修改每個項目的值。
如何才能做到這一點?
如果要在編譯時禁止修改操作,則需要類型安全的解決方案。
為公開允許的操作聲明接口。 使用該接口作為屬性類型。
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而不是List,因此接口可能需要
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; }
}
我已經讓它繼承了IEnumerable,無論如何都是readonly,所以非常安全。 安全課程將是:
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; }
}
當然,現在這個界面的名稱是錯誤的...為什么你想要禁止通過添加添加但不通過索引器禁止它? (索引器可用於添加項目,就像Add方法一樣。)
更新
從您的評論中我認為您的意思是您希望允許分配現有鍵/值對的值,但不允許分配給以前未知的鍵。 顯然,因為鍵是在運行時通過字符串指定的,所以在編譯時無法捕獲它。 所以你也可以去運行時檢查:
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
}
任何時候你有一個普通的字典,並且你想把它交給一些你不信任更新現有值的方法,請將其包裝在其中一個中。
編輯:原始答案如下。 正如耳語所指出的那樣,我沒有注意到你並不是要求它只讀 - 只是為了防止Add
操作。 這對我來說聽起來不是一個好主意,因為Add
和indexer-setter之間的唯一區別是如果元素已經存在,則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(key)添加到包裝類中。 然后將SortedList保持為類的私有。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.