"Force-casting" a returned type
This should be a pretty trivial one.
Can C# return a type that is "force-cast", that is where the following fails:
private ICollection<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
get
{
return ((IEnumerable<string>)_strings);
}
}
/* I should not know that Strings can be cast to ICollection */
public void AddToStrings()
{
ICollection<string> st = ((ICollection<string>)Strings); /* I should fail */
st.Add("MyString");
}
I'm aware I could do this:
public IEnumerable<string> Strings
{
get
{
return ((IEnumerable<string>)_strings.ToArray());
}
}
But this seems (1) unnecessary, (2) still doesn't stop them casting to an ICollection, just from adding and (3) I'm just plain curious about the general question.
Clarification
Some people seem unsure about what I am trying to achieve here. I am trying to prevent outside classes from violating the contract I provide them. I have not said that Strings is an ICollection - it just so happens that I am using that internally - and as such no outside class should be able to treat my returned variable as an ICollection. I don't want to expose modification behaviour to them, and I don't want them to treat my variable as an ICollection in case I later change the way I generate that IEnumerable.
More generally, can I return an object as an instance of one of its more specific types, and prevent later casting to one of its more general types. For example, while you can yield a new IEnumerable, could you return an IDisposable object that cannot be cast back to whatever type it was (i.e. only has Di开发者_如何学Cspose() and object methods callable)?
Ah ok, I see what you mean now...
public IEnumerable<string> Strings
{
get
{
foreach (var s in _strings) yield return s;
}
}
But it has nothing to do with boxing...
Thomas provided you the correct answer, for this specific instance.
That being said, there is no "general purpose" way to prevent users from attempting to cast types to their "actual" type instead of an interface you provide them.
The closest thing you can do is use types that are internal within your assembly, and not visible to the caller. This will prevent the user from being able to use your type directly (at least without resorting to reflection in elevated trust situations).
However, in general, I would suggest not worrying about this. Any user who casts your type to an undocumented, internal implementation detail's type is just asking for trouble, and I would not try to code a way of preventing this. Doing so is just doing yourself a disservice, since you're making your code less maintainable.
In this specific case where you return an IEnumerable Thomas's solution using yield is probably the best. In the general case where the returned interface might be anything (like IDisposable as you mentioned in your edit) the only way to achieve what you want would be to create a wrapper class that implements the given interface using delegation (e.g. a class MyDisposable that holds an IDisposable
and implements the Dispose method by calling Dispose on the IDisposable it holds).
精彩评论