C# 如何为集合创建公共 getter 和 setter 以及私有方法?
我想要一个带有(例如)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”来填充“Parameters”集合,因此只能修改每个项目的值。
如何才能做到这一点?
I'd like to have a class "A" with a (for example) SortedList collection "SrtdLst" property, and inside this class "A" allow the addition or subtraction of "SrtdLst" items. But in a instance of the class "A", only allow to get or set the content of the items, not to add new items or subtract the existing ones. In code:
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";
}
}
UPDATE: I want to create a class like System.Data.SqlClient.SqlCommand. For the Stored Procedures you can use the member "DeriveParameters" that fills a collection of "Parameters", so only the value of each item can be modified.
How can this be done?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果你想在编译时禁止修改操作,你需要一个类型安全的解决方案。
为公共允许的操作声明一个接口。 使用该接口作为属性类型。
然后声明一个实现该接口并继承自标准集合类的类。
假设您正确定义了接口,则无需手动实现任何内容,因为基类已经提供了实现。
使用该派生类作为存储属性值的字段的类型。
在A类中,可以直接使用
_list
,从而修改内容。 A 类客户端只能使用通过IReadOnlyList
提供的操作子集。对于您的示例,您使用的是 SortedList 而不是 List,因此接口可能需要
我也使其继承 IEnumerable,无论如何它都是只读的,因此非常安全。 安全类将是:
但除此之外,这是相同的想法。
更新:只是注意到(由于某种原因我无法理解)你不想禁止修改操作 - 你只是想禁止一些修改操作。 很奇怪,但它仍然是相同的解决方案。 无论您想要允许什么操作,都可以在界面中“打开它们”:
当然,现在界面的名称是错误的...到底为什么您要禁止通过 Add 添加而不是通过索引器禁止它? (索引器可用于添加项目,就像 Add 方法一样。)
更新
从您的评论中我认为您的意思是您希望允许分配给现有键/值对的值,但不允许分配给以前未知的键。 显然,由于键是在运行时由字符串指定的,因此无法在编译时捕获它。 因此,您也可以进行运行时检查:
任何时候您有一个普通字典,并且想要将其交给您不信任的某个方法来更新现有值,请将其包装在其中之一中。
If you want to ban the modifying operations at compile time, you need a type-safe solution.
Declare an interface for the publicly allowed operations. Use that interface as the property type.
Then declare a class that implements that interface and inherits from the standard collection class.
Assuming you get the interface definition right, you won't need to implement anything by hand, as the base class already provides the implementations.
Use that derived class as the type of the field that stores the property value.
Within class A, you can use
_list
directly, and so modify the contents. Clients of class A will only be able to use the subset of operations available viaIReadOnlyList<T>
.For your example, you're using SortedList instead of List, so the interface probably needs to be
I've made it inherit IEnumerable as well, which is readonly anyway, so is perfectly safe. The safe class would then be:
But otherwise it's the same idea.
Update: just noticed that (for some reason I can't fathom) you don't want to ban modifying operations - you just want to ban SOME modifying operations. Very strange, but it's still the same solution. Whatever operations you want to allow, "open them up" in the interface:
Of course, that's the wrong name for the interface now... why on earth would you want to ban adding via Add but not ban it via the indexer? (The indexer can be used to add items, just as the Add method can.)
Update
From your comment I think you mean that you want to allow assignment to the value of an existing key/value pair, but disallow assignment to a previously unknown key. Obviously as keys are specified at runtime by strings, there's no way to catch that at compile time. So you may as well go for runtime checking:
Any time you have an ordinary dictionary and you want to hand it to some method that you don't trust to update the existing values, wrap it in one of these.
编辑:原始答案如下。 正如earwicker 指出的那样,我没有注意到您没有要求它是只读的 - 只是为了防止
Add
操作。 对我来说,这听起来不是一个好主意,因为Add
和索引器设置器之间的唯一区别是,如果元素已经存在,Add
会抛出异常。 无论如何,这很容易被呼叫者伪造。为什么要限制这一项操作?
原始答案
一方面,不要使用公共字段。 这肯定会遇到问题。
看起来您想要一个围绕任意
IDictionary
的只读包装类。 然后,您可以拥有一个返回包装器的公共属性,同时从类中访问私有变量。 例如:现在您只需找到一个 ReadOnlyDictionary 实现...我现在无法实现它,但如果需要的话我稍后会回来...
EDIT: Original answer is below. As earwicker points out, I hadn't noticed that you aren't asking for it to be readonly - just to prevent the
Add
operation. That doesn't sound like a good idea to me, as the only difference betweenAdd
and the indexer-setter is thatAdd
throws an exception if the element is already present. That could easily be faked up by the caller anyway.Why do you want to restrict just that one operation?
Original answer
For one thing, don't use public fields. That's a surefire way to run into problems.
It looks like you want a read-only wrapper class round an arbitrary
IDictionary
. You can then have a public property which returns the wrapper, while you access the private variable from within your class. For example:Now you've just got to find a
ReadOnlyDictionary
implementation... I can't implement it right now, but I'll be back later if necessary...只需将列表设为私有,并将其公开为索引器:
现在您只能使用索引访问项目:
但是,由于列表的索引器允许创建新项目,因此您必须在索引器中添加代码以防止出现这种情况如果你不想那样做也是可能的。
Just make the list private, and expose it as an indexer:
Now you can only access the items using the index:
However, as the indexer of the list allows creation of new items, you would have to add code in the indexer to prevent that if you don't want that do be possible.
如果键在类外部已知,则可以将 ChangeItem(key, newValue) 和 ReadItem(key) 添加到包装类中。 然后将 SortedList 保留为类的私有。
If the keys are known outside of the class then you can add a ChangeItem(key, newValue) and ReadItem(key) to your wrapper class. Then keep the SortedList private to the class.