[英]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.