C#如何使收集公共getter和setter方法和私有方法?
-
22-08-2019 - |
题
我想有一个类“A”与(例如)排序列表集“SrtdLst”属性,并且这类中“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>
使用可用的操作的子集。
有关你的榜样,你正在使用排序列表而不是列表,所以接口可能需要在
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; }
}
我将它继承了IEnumerable为好,这是只读的,无论如何,所以是绝对安全的。然后,安全的类将是:
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
}
您有任何时间一个普通的字典,并且希望把它交给一些你不信任更新现有的值,把它包在其中的一个方法。
其他提示
编辑:原来的答复如下。正如埃里克指出,我没有注意到你的不的要求它是只读的 - 只是为了防止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(键,NEWVALUE)和ReadItem(键),在包装类。然后保持SortedList的私有类。