Is it safe to expose an IEnumerable in a property? - c#

If I expose an IEnumerable<T> as a property of a class, is there any possibility that it can be mutated by the users of a class, and if so what is the best way of protecting against mutation, while keeping the exposed property's type IEnumerable<T>?

It depends on what you're returning. If you return (say) a mutable List<string> then the client could indeed cast it back to List<string> and mutate it.
How you protect your data depends on what you've got to start with. ReadOnlyCollection<T> is a good wrapper class, assuming you've got an IList<T> to start with.
If your clients won't benefit from the return value implementing IList<T> or ICollection<T>, you could always do something like:
public IEnumerable<string> Names
{
get { return names.Select(x => x); }
}
which effectively wraps the collection in an iterator. (There are various different ways of using LINQ to hide the source... although it's not documented which operators hide the source and which don't. For example calling Skip(0) does hide the source in the Microsoft implementation, but isn't documented to do so.)
Select definitely should hide the source though.

The user may be able to cast back to the collection class, so expose.
collection.Select(x => x)
and this will get a new IEnumerable created that can't be cast to the collection

The collection can be cast back to the original type and if it is mutable then it can then be mutated.
One way to avoid the possibility of the original being mutated is returning a copy of the list.

I would not suggest wrapping an IEnumerable in an iterator to prevent recipients from monkeying with the underlying connection. My inclination would be to use a wrapper something like:
public struct WrappedEnumerable<T> : IEnumerable<T>
{
IEnumerable<T> _dataSource;
public WrappedEnumerable(IEnumerable<T> dataSource)
{
_dataSource = dataSource;
}
public IEnumerator<T> GetEnumerator()
{
return _dataSource.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((System.Collections.IEnumerable)_dataSource).GetEnumerator();
}
}
If the return type of the properties is IEnumerable<T>, the type coercion from WrappedEnumerable<T> to IEnumerable<T> would box the structure and make the behavior and performance match those of a class. If, however, the properties, were defined as returning type WrappedEnumerable<T>, then it would be possible to save a boxing step in cases where the calling code either assigns the return to a property of type WrappedEnumerable<T> (most likely as a result of something like var myKeys = myCollection.Keys;) or simply uses the property directly in a "foreach" loop. Note that if the enumerator returned by GetEnumerator() would be a struct, that will still have to be boxed in any case.
The performance advantage of using a struct rather than a class would generally be fairly slight; conceptually, however, using a struct would fit with the general recommendation that properties not create new heap object instances. Constructing a new struct instance which contains nothing but a reference to an existing heap object is very cheap. The biggest disadvantage to using a struct as defined here would be that it would lock in the behavior of the thing returned to the calling code, whereas simply returning IEnumerable<T> would allow other approaches.
Note also that it may in some cases be possible to eliminate the requirement for any boxing and exploit the duck-typing optimizations in C# and vb.net foreach loop if one used a type like:
public struct FancyWrappedEnumerable<TItems,TEnumerator,TDataSource> : IEnumerable<TItems> where TEnumerator : IEnumerator<TItems>
{
TDataSource _dataSource;
Func<TDataSource,TEnumerator> _convertor;
public FancyWrappedEnumerable(TDataSource dataSource, Func<TDataSource, TEnumerator> convertor)
{
_dataSource = dataSource;
_convertor = convertor;
}
public TEnumerator GetEnumerator()
{
return _convertor(_dataSource);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _convertor(_dataSource);
}
}
The convertor delegate could be a static delegate, and thus not require any heap-object creation at run-time (outside class initialization). Using this approach, if one wanted to return an enumerator from a List<int>, the property return type would be FancyWrappedEnumerable<int, List<int>.Enumerator, List>. Perhaps reasonable if the caller just used the property directly in a foreach loop, or in a var declaration, but rather icky if the caller wanted to declare a storage location of the type in a way that couldn't use var.

Related

ArraySegment must be cast to IList to iterate through it with an Index. Is there a way to hide the irrelevant IList methods?

To be able to treat ArraySegment directly like an array, you must cast it to IList with "as". This is described as the proper behavior here:
use of ArraySegment class?
and here:
dotNet ArraySegment Struct
Specifically, Microsoft document says:
If you want to retrieve an element by its index in the ArraySegment
object, you must cast it to an IList object and retrieve it or
modify it by using the IList.Item[Int32] property. The following
example retrieves the element in an ArraySegment object that
delimits a section of a string array.
What's perplexing is that IList has methods like "Remove" and "RemoveAt". You would expect those to not work on an arraysegment cast as a List. I tested this, and in fact calling Remove throws a runtime error. But the compiler doesn't catch the problem.
I'm surprised that Microsoft considered this acceptable behavior in the design of ArraySegment.
I was trying to brainstorm a wrapper class or some way to hide the List methods that shouldn't be called on the ArraySegment as List. But I couldn't come up with anything.
Does anyone have a suggestion on how to fix this?
EDIT: IReadOnlyList has been suggested instead of IList.
IReadOnlyList causes the List to completely read-only, preventing you from modifying the value of elements stored in underlying array. I want to be able to modify the original array values. I just don't want to be able to write list.Remove() or list.Add() since it's clearly wrong and the compiler shouldn't be allowing it.
To anyone who might suggest Span as an alternative:
I am aware of Span, but Span currently has limitations in .NET Framework and Standard. Specifically, it can only be used as a local variable, and thus cannot be passed to other methods.
And to be honest, I actually think Microsoft's IEnumerable heirarchy leaves a bit to be desired -- I can't figure out any way to make an Indexable sequence like List without it offering Add/Remove functionality. ICollection doesn't support Indexing. If anyone has suggestions on that issue itself, I'm all ears.
Turns out, in .NET 4.7.2, the ArraySegment<T> doesn't expose an indexer unless if it's cast to the IList<T> interface, but it does in .NET Core 2.1.
You may cast to the IReadOnlyList<T> interface; note that it doesn't prevent you from changing the contained objects themselves if they are mutable:
The IReadOnlyList<T> represents a list in which the number and order of list elements is read-only. The content of list elements is not guaranteed to be read-only.
So, it only guarantees that the collection itself (the container) is immutable (no adds, removes, replacements). You can't replace an element because the indexer doesn't have a setter.
There's also the ReadOnlyCollection<T> wrapper class (add using System.Collections.ObjectModel;). Also no setter on the indexer though.
If none of these work for you, and you want to implement a wrapper, just create a class that takes in an IList<T> in the constructor, and implement your own indexer. I'd also implement IEnumerable<T>, so that you get LINQ support, and it will also make it work with the foreach loop.
// Add these...
using System.Collections;
using System.Collections.Generic;
//...
public class MyWrapper<T> : IEnumerable<T>
{
private IList<T> _internalList;
public MyWrapper(IList<T> list)
{
_internalList = list;
}
public int Count => _internalList.Count;
// the indexer
public T this[int index]
{
get => _internalList[index];
set => _internalList[index] = value;
}
public IEnumerator<T> GetEnumerator()
{
return _internalList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
And then just pass the array segment to the constructor (without casting).
P.S. If this is some internal code, used in few places only, writing a wrapper may or may not be worth the trouble; it's OK to use an IList<T> as long as its clear what the intention was.
Also, if you don't mind working with a copy of the array that's only limited to the range defined by the array segment, and if the copy operation cost is not a concern, you can call either the ToArray or ToList extension method on the segment. But I suspect you want the original array to be updated and you just need a "window" into a segment.
You can still use ArraySegment, which will prevent adding/removing items and access/update items by index through .Array property
var numbers = new[] { 1, 2, 3, 4 };
var segment = new ArraySegment<int>(numbers);
segment.Array[2] = 101;
// segment contains now { 1, 2, 101, 4}
You can always create extension methods to improve readability
public static void UpdateAt<T>(this ArraySegment<T> segment, int index, T value)
{
segment.Array[index] = value;
}
You can create extension methods that allow calling the indexer directly, without unnecessary boxing:
public static T Get<T>(this ArraySegment<T> segment, int index)
{
return GetList<ArraySegment<T>, T>(segment, index);
}
private static T GetList<TList, T>(TList list, int index) where TList : struct, IReadOnlyList<T>
{
return list[index];
}
public static void Set<T>(this ArraySegment<T> segment, int index, T value)
{
SetList<ArraySegment<T>, T>(segment, index, value);
}
private static void SetList<TList, T>(TList list, int index, T value) where TList : struct, IReadOnlyList<T>
{
list[index] = value;
}
Sadly extension indexers are not yet possible, but this at least allows to use the provided indexer in a convenient and fast way.

A const list in C#

I would like to create a list in C# that after its creation I won't be able to add or remove items from it. For example, I will create the list;
List<int> lst = a;
(a is an existing list), but after I won't be able to write the code (it will mark it as an error):
lst.Add(2);
.NET supports truly immutable collections, read-only views of mutable collections, and read-only interfaces implemented by mutable collections.
One such immutable collection is ImmutableArray<> which you can create as a.ToImmutableArray() in your example. Make sure to take a look at the other options MSDN lists because you may be better served by a different immutable collection. If you want to make copies of the original sequence with slight modifications, ImmutableList<> might be faster, for instance (the array is cheaper to create and access, though). Note that a.Add(...); is valid, but returns a new collection rather than changing a. If you have resharper, that will warn you if you ignore the return value of a pure method like Add (and there may be a roslyn extension to do something similar I'm unaware of). If you're going this route - consider skipping List<> entirely and going straight to immutable collections.
Read-only views of mutable collections are a little less safe but supported on older versions of .NET. The wrapping type is called ReadOnlyCollection<>, which in your example you might construct as a.AsReadOnly(). This collection does not guarantee immutability; it only guarrantees you can't change it. Some other bit of code that shares a reference to the underlying List<> can still change it. Also, ReadOnlyCollection also imposes some additional overhead; so you may not be winning much by avoiding immutable collections for performance reasons (TODO: benchmark this claim). You can use a read-only wrapper such as this even in a public API safely - there's no (non-reflection) way of getting the underlying list. However, since it's often no faster than immutable collections, and it's also not entirely safe, I recommend to avoid ReadOnlyCollection<> - I never use this anymore, personally.
Read-only interfaces implemented by mutable collections are even further down the scale of safety, but fast. You can simply cast List<> as IReadOnlyList<>, which you might do in your example as IReadOnlyList<int> lst = a. This is my preferences for internal code - you still get static type safety, you're simply not protected from malicious code or code that uses type-checks and casts unwisely (but those are avoidable via code-reviews in my experience). I've never been bitten by this choice, but it is less safe than the above two options. On the upside, it incurs no allocations and is faster. If you commonly do this, you may want to define an extension method to do the upcast for you (casts can be unsafe in C# because they not only do safe upcasts, but possibly failing downcasts, and user-defined conversions - so it's a good idea to avoid explicit casts wherever you can).
Note that in all cases, only the sequence itself is read-only. Underlying objects aren't affected (e.g. an int or string are immutable, but more complicated objects may or may not be).
TL;DR:
For safety: Use a.ToImmutableArray() to create an immutable copy in an ImmutableArray<int>.
For performance: Use IReadOnlyList<int> to help prevent accidental mutation in internal code with minimal performance overhead. Be aware that somebody can cast it back to List<> (don't do that), making this less "safe" for a public api.
Avoid a.AsReadOnly() which creates a ReadOnlyCollection<int> unless you're working on a legacy code base that doesn't support the newer alternatives, or if you really know what you're doing and have special needs (e.g. really do want to mutate the list elsewhere and have a read-only view).
You can use ImmutableList<T> / ImmutableArray<T> from System.Collections.Immutable NuGet:
var immutable = ImmutableList<int>.Create(1, 2, 3);
Or using the ToImmutableList extension method:
var immutable = mutableList.ToImmutableList();
In-case Add is invoked, *a new copy * is returned and doesn't modify the original list. This won't cause a compile time error though.
You need a ReadonlyCollection. You can create one from a list by calling List.AsReadOnly()
Reference: https://msdn.microsoft.com/en-us/library/ms132474.aspx
Why not just use an IEnumerable?
IEnumerable<string> myList = new List<string> { "value1", "value2" };
I recommend using a System.Collections.Immutable.ImmutableList<T> instance but referenced by a variable or property of type System.Collections.Generic.IReadOnlyList<T>. If you just use a naked immutable list, you won't get errors for adding to it, as you desire.
System.Collections.Generic.IReadOnlyList<int> list = a.ToImmutableList();
As an alternative to the already posted answers, you can wrap a readonly regular List<T> into an object that exposes it as IReadOnlyList.
class ROList<T>
{
public ROList(IEnumerable<T> argEnumerable)
{
m_list = new List<T>(argEnumerable);
}
private readonly List<T> m_list;
public IReadOnlyList<T> List { get { return m_list; } }
}
void Main()
{
var list = new List<int> {1, 2, 3};
var rolist = new ROList<int>(list);
foreach(var i in rolist.List)
Console.WriteLine(i);
//rolist.List.Add(4); // Uncomment this and it won't compile: Add() is not allowed
}
Your best bet here is to use an IReadOnlyList<int>.
The advantage of using IReadOnlyList<int> compared to List.AsReadOnly() is that a ReadOnlyCollection<T> can be assigned to an IList<T>, which can then be accessed via a writable indexer.
Example to clarify:
var original = new List<int> { 1, 2, 3 };
IReadOnlyList<int> readOnlyList = original;
Console.WriteLine(readOnlyList[0]); // Compiles.
readOnlyList[0] = 0; // Does not compile.
var readOnlyCollection = original.AsReadOnly();
readOnlyCollection[0] = 1; // Does not compile.
IList<int> collection = readOnlyCollection; // Compiles.
collection[0] = 1; // Compiles, but throws runtime exception.
Using an IReadOnlyList<int> avoids the possibility of accidentally passing the read-only list to a method which accepts an IList<> and which then tries to change an element - which would result in a runtime exception.
It could be IReadOnlyList<int>, e.g.
IReadOnlyList<int> lst = a;
So the initial list (a) is mutable while lst is not. Often we use IReadOnlyList<T> for public properties and IList<T> for private ones, e.g.
public class MyClass {
// class itself can modify m_MyList
private IList<int> m_MyList = new List{1, 2, 3};
...
// ... while code outside can't
public IReadOnlyList<int> MyList {
get {
return m_MyList;
}
}
}
Why not just:
readonly IEnumerable<int> lst = new List<int>() { a }

Return Type of Method Not Matching Type of Variable Returned, But Still Works

I am trying to wrap my head around all the list Interfaces in C# (IEnumarable, IReadOnlyCollection) etc., and as part of that realized I do not really understand why the below code works. After all, the method has an IReadOnlyCollection as return type, but the varibale returned is of type Array (float[]). I realize that Array implements the IReadOnlyCollection interface, but I do not get how it converts from one to the other. Is it done in the background somehow?
private readonly float[] _location;
public Player()
{
_location = new float[3];
}
public IReadOnlyCollection<float> Location
{
get
{
_location[0] = Worker.Elements["lbXCoordinate"].Value;
_location[1] = Worker.Elements["lbYCoordinate"].Value;
_location[2] = Worker.Elements["lbZCoordinate"].Value;
return _location;
}
}
An object can be implicitly casted to any one of the interfaces that is implemented by its class; however, no conversion takes place - as Jon Skeet pointed out in a comment, it is the original array that is returned. To the caller, it will be "disguised" as an IReadOnlyCollection<float>, and the caller will ideally only perform operations from IReadOnlyCollection<float> on it. However, if the caller knows or suspects the actual type, the caller may decide to cast it back into a float[], and the encapsulation of your object will be breached. (This is risky for the caller, though, since if you change the actual type to List<float> at some point, the code that casts to float[] will break.) In order to ensure encapsulation, the object that is returned must itself protect its contents, so you should indeed create a class/struct with private (or no) setters. Then, your code will become more readable and self-documenting as well.
The above code works, because IReadOnlyCollection interface implements IEnumerable and Array abstract class also implements IEnumerable interface. So when you, return array of float for a method of IReadOnlyCollection return type, an upcasting is done internally to IEnumerable.
I hope this is what you are looking for.
No, Array does not implement IReadOnlyCollection, please refer below link:
http://msdn.microsoft.com/en-IN/library/system.array(v=vs.110).aspx
And IReadOnlyCollection also implements same Interface IEnumerable, please refer below link:
http://msdn.microsoft.com/en-us/library/hh881542(v=vs.110).aspx
Now, when you are trying to return an array for a method of type, IReadOnlyCollection, it is a type safe conversion to their base type which is IEnumerable.

What is the requirement for a collection in order that we can put a foreach on it?

What is the requirement for a collection in order that we can put a foreach on it in c#? What are the types on which we can put for each?
EDIT 1: Can anybody come up with a sample code of a User Defined Collection on which Foreach is Implemented.
It implements IEnumerable or IEnumerable<T>
Edit: there is the wrinkle that if the type has method called GetEnumerator() that returns an IEnumerator then it is also usable in a foreach. see http://brendan.enrick.com/post/Foreach-IEnumerable-IEnumerator-and-Duck-Typing.aspx
What is generally accepted is that you need implementation of IEnumerable or IEnumerable<T> but you can read from Eric's post Following the pattern that it is not the case as such
What is required is that the type of the collection must have a public
method called GetEnumerator, and that must return some type that has a
public property getter called Current and a public method MoveNext
that returns a bool.
The only formal requirement is that it has a method called GetEnumerator(), which returns something which has a SomeType Current {get;} property and a bool MoveNext() method. Most commonly, however, this is done by implementing the IEnumerable/IEnumerable<T> interface. Indeed, it is expected that you will implement this interface (the older method was really intended as a pre-generics optimisation), and using the interface will allow consumers to use your collection with things like LINQ and collection-initializers.
In interesting cases, the easiest way of implementing such is via an "iterator block". For example:
class Foo : IEnumerable<int> {
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public IEnumerator<int> GetEnumerator() {
yield return 16;
yield return 12;
yield return 31;
// ^^ now imagine the above was a loop over some internal structure -
// for example an array, list, linked-list, etc, with a "yield return"
// per item
}
}

Generic method to cast one arbitrary type to another in c#

I want to do something like this:
public static TResult MyCast<TSource, TResult>(TSource item)
{
return (TResult)item;
}
Without restrictions on TSource or TResult and avoiding unnecessary boxing if possible.
Edit: I want to stress out, that I want a simple casting of types, not elaborate type conversion here. It would be perfectly ok to fail at casting, say string to int.
Is there any sane way to do this using CLR 2.0?
Edit: this is a simplified version, so it's pretty useless, yes.
But consider casting generic collections, such as this:
public static Dictionary<string, TResult> CastValues<TSource, TResult>(this Dictionary<string, TSource> dictionary)
After some discussions with my co-workers, it seems like there's no simple way to implement such a feature (if at all possible), so I'm stuck with code bloat of several very simple methods for different situations (i.e. up- and downcast of reference types and casting of some value types) :(
Too bad I can't use .NET 4.0 with all it's dynamic et al goodness.
How would
x = MyCast<SourceType, ResultType>(y)
be any more useful than
x = (ResultType)y ?
This is straightforward when TSource and TResult are both reference types.
If one or the other are value types, how do you want it to work? Value types can't inherit from each other, so it's not a matter of doing an up- or down-cast. You might expect numeric conversions between, say, int and double, but you'd have to code these yourself: .NET doesn't treat them as typecasts. And conversion between, say, DateTime and string involves more intelligence (what format? which culture? etc.).
If you're just handling reference types then this method can be a one-liner. If you want to handle value types as well then you'll need to write special case code for the various combinations.
Edit: Convert.ChangeType does a reasonable job at encapsulating the various conversions between value types. However you mentioned you're keen not to introduce boxing: Convert.ChangeType isn't generic and it takes an object.
I think that the problem you are trying to solve is the same as the problem that you cannot cast a collection of one type to a collection of another type.
eg
class Obj1
{}
class Obj2:Obj1
{}
List<Obj2> srcList = GetList();
List<Obj1> castedList=(List<Obj2>) srcList;//this line wont compile
I have not done much at actually looking at the CLR code
However on the asuumption that it is like C++ what you would have here is actually different values stored in the collection. In other words srcList would contain a list of pointers to object 2's interface in castedList you would have a pointer to the the interface of the object 1's within object 2.
In order to resolve this you would need to have your casting function iterate through each of the items within the collection. However in order to be able to iterate through the items the list would have to implement some sort of enumeration interface. So the enumeration interface would need to be a constraint on the casting function.
So the answer would therefore be no.
However if you were prepared to implement this with restrictions on the in types you could have:
static class ListCast<TSource,TResult,TItemType>
where TSource:IEnumerable<TItemType>
where TResult:IList<TItemType>,new()
{
static TResult Cast(TSource list)
{
TResult castedList=newTResult();
foreach(TtemType item in list)
{
castedList.Add(TItemType)item);
}
return castedList;
}
}
you can just do this:
public static TResult MyCast<TSource, TResult>(TSource item)
{
return (TResult)((object)item);
}
Would love to hear how this could be bad.

Categories