I have a class property exposing an internal IList<> through
System.Collections.ObjectModel.ReadOnlyCollection<>
How can I pass a part of this ReadOnlyCollection<> without copying elements into a new array (I need a live view, and the target device is short on memory)? I'm targetting Compact Framework 2.0.
Try a method that returns an enumeration using yield:
IEnumerable<T> FilterCollection<T>( ReadOnlyCollection<T> input ) {
foreach ( T item in input )
if ( /* criterion is met */ )
yield return item;
}
These foreach samples are fine, though you can make them much more terse if you're using .NET 3.5 and LINQ:
return FullList.Where(i => IsItemInPartialList(i)).ToList();
You can always write a class that implements IList and forwards all calls to the original list (so it doesn't have it's own copy of the data) after translating the indexes.
You could use yield return to create a filtered list
IEnumerable<object> FilteredList()
{
foreach( object item in FullList )
{
if( IsItemInPartialList( item )
yield return item;
}
}
Depending on how you need to filter the collection, you may want to create a class that implements IList (or IEnumerable, if that works for you) but that mucks about with the indexing and access to only return the values you want. For example
class EvenList: IList
{
private IList innerList;
public EvenList(IList innerList)
{
this.innerList = innerList;
}
public object this[int index]
{
get { return innerList[2*i]; }
set { innerList[2*i] = value; }
}
// and similarly for the other IList methods
}
How do the filtered elements need to be accessed? If it's through an Iterator then maybe you could write a custom iterator that skips the elements you don't want publicly visible?
If you need to provide a Collection then you might need to write your own Collection class, which just proxies to the underlying Collection, but prevents access to the elements you don't want publicly visible.
(Disclaimer: I'm not very familiar with C#, so these are general answers. There may be more specific answers to C# that work better)
Related
I am still learning the basics of C# and found a task where you have to implement the method below, it is supposed to return the same sequence of strings but uppercase, and I assume by sequence it means an array.
But I am also somehow supposed to use IEnumerable for this.
I thought IEnumerable was an interface, how is it a type and a parameter in that method I am supposed to add logic into?
I searched and found that return type IEnumerable means it has to return something that can implement IEnumerable, but the parameters still confuse me, how do I use them to return uppercase? Do I use a foreach ?
using System;
using System.Collections.Generic;
namespace EnumerableTask
{
public class EnumerableManipulation
{
/// <summary> Transforms all strings to upper case.</summary>
/// <param name="data">Source string sequence.</param>
public IEnumerable<string> GetUppercaseStrings(IEnumerable<string> data)
{
}
}
You can use Linq Select() which would return an IEnumerable. ie:
public IEnumerable<string> GetUppercaseStrings(IEnumerable<string> data)
{
return data.Select(d => d.ToUpper());
}
EDIT: You can check Linq documentation or my blog starting from the oldest post (Feb 2009) at:
FoxSharp
You can also use foreach and yield:
public IEnumerable<string> GetUppercaseStrings(IEnumerable<string> data)
{
foreach (var item in data)
yield return item?.ToUpper();
}
IEnumerable<T> is a generic interface. It represents a collection of objects of type T. In your case, data is a collection of string that can be enumerated.
Enumerate a IEnumerable
To enumerate through the 'data' and acccess the elements one after the others, there is several possibilities. Here are two examples.
GetEnumerator()
GetEnumerator() gives you a way to enumerate through the IEnumerable<T>. enumerator.Current allows you to access the current element and enumerator.MoveNext() gives you a way to move to the next element in the collection.
At first use call MoveNext() method to place the enumerator at the first element of the IEnumerable<T>. While there is still elements to enumerate, MoveNext() will return true. When the end is reached, MoveNext() returns false.
Here is an example of how it is typically used.
IEnumerator<string> enumerator = data.GetEnumerator();
while(enumerator.MoveNext())
{
string text = data.Current;
/* Do something */
}
enumerator.Dispose();
foreach
Using foreach takes care of all the complexity of the enumerator process. It is in fact recommended to use foreach instead of directly manipulating the enumerator (see Microsoft Docs, in Remarks).
foreach(string text in data)
{
/* Do something */
}
Return a IEnumerable
Because IEnumerable<T> is an interface, you cannot "construct" it as you would with a class or a struct. Hence to return a IEnumerable<T>, you have to instanciate an actual class or a struct that implements this interface. For example:
public IEnumerable<string> Foo()
{
List<string> list = new List<string>();
/* Do something on the list*/
return list;
}
or
public IEnumerable<string> Foo(int count)
{
string[] array = new string[count];
/* Do something on the array*/
return array;
}
You can do this because List<T> and Array implement the interface IEnumerable<string>.
Forgive me is this is a noob question. I am new to C# and am confused by the use of IEnumerables. I am trying to iterate through a list of objects but the normal foreach method to which I am familiar doesn't work for perhaps obvious reasons. Can somebody give me an example of implementing code which iterates through a list of objects using an IEnumerable?
EDIT
class MyObjects : IEnumerable<LIST>
{
List<LIST> myTeam = new List<GroupMember>();
public LIST this[int index]
{
get { return myTeam[index]; }
}
public IEnumerator<LIST> GetEnumerator()
{
return myTeam.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<GroupMember> IEnumerable<GroupMember>.GetEnumerator()
{
throw new NotImplementedException();
}
}
The above code is what I have implemented so far. I tried iterating through a returned list using foreach but it didn't work and further research revealed that I have to explicitly define the list as enumerable etc. I am just lost as to how that is achieved. And yes, nothing is obvious when you don't know what you are doing.
So, to summarise, I can call a function which returns a list of objects. I want to be able to iterate through that list of objects so that I can access values within it.
Iterate through a range of numbers 1 to 10...
foreach (var i in Enumerable.Range(1, 10))
{
//Do something with i
}
If I try to cast an object of type EntityCollection<MyNamespace.Models.MyEntityClass> to ICollection<Object> I get an InvalidCastException.
Okay, according to the docs, EntityCollection<TEntity> implements ICollection<T>, and MyNamespace.Models.MyEntityClass must descend from Object, right? So why on earth does this fail?
FWIW, I'm trying to do this in a method that generally can add and remove items from what might be an EntityCollection or some other IList or ISet. I need to preserve the change tracking behavior of EntityCollection, because the object is to eventually be able to commit the changes if it's an EC.
Edit
Okay, here's some more specifics of what I'm doing. I'm deserializing JSON, and the target object can have properties that are collections--maybe they're EntityCollections, maybe not. For the sake of simplicity, lets say the members of the collection are always subclasses of EntityObject, whether it's an EntityCollection or not (if I understand the responses so far, I'd have no better luck casting to ICollection<EntityObject> than to ICollection<Object>…right?). This is the part where I run into trouble…
foreach (PropertyInfo prop in hasManys)
{
// This is where I get the InvalidCastException...
ICollection<Object> oldHms = (ICollection<Object>)prop.GetValue(parentObj, null);
JEnumerable<JToken> hmIds = links[FormatPropName(prop.Name)].Children();
if (hmIds.Count() == 0)
{
// No members! Clear it out!
oldHms.Clear();
continue; // breaking early!
}
relType = prop.PropertyType.GetGenericArguments()[0];
// Get back the actual entities we'll need to put into the relationship...
List<EntityObject> newHms = new List<EntityObject>();
foreach (JToken jt in hmIds)
{
// ...populate newHms with existing EntityObjects from the context...
}
// first, delete any missing...
/* Got to use ToList() to make a copy, because otherwise missings is
* still connected to the oldHms collection (It's an ObjectQuery)
* and you can't modify oldHms while enumerating missings.
*/
// This cast will fail too, right? Though it's more easily fixable:
IEnumerable<EntityObject> missings = ((ICollection<EntityObject>)oldHms).Except(newHms).ToList();
foreach (EntityObject missing in missings)
{
oldHms.Remove(missing); // One of my mutable collection operations
}
// add new ones
foreach (EntityObject child in newHms)
{
if (!oldHms.Contains(child)) // Skip if already in there
{
oldHms.Add(child); // another mutable collection operation
}
}
}
}
That's a bit simplified, I have special cases for Arrays (implement ICollection, but aren't generics) and other stuff that I took out. Point is, I need to operate Clear, Add, and Remove on the EntityCollection itself--if that's what it is. Maybe there's another way to do this type of synchronization that I'm missing?
read-write collections cannot be variant.
Take this example:
List<MyClass> list1 = new List<MyClass>();
// assume this would work
ICollection<object> list2 = list1;
list2.Add(new object()); // ooops. We added an object to List<MyClass>!
In principal this kind of casting is only possible for "read-only" interfaces (allowing covariance) or for "write-only" interfaces (allowing contravariance).
One "solution" would involve a wrapper class like this:
public class Wrapper<T> : ICollection<object>
{
private readonly ICollection<T> collection;
public Wrapper(ICollection<T> collection)
{
this.collection = collection;
}
public void Add(object item)
{
// maybe check if T is of the desired type
collection.Add((T)item);
}
public void Clear()
{
collection.Clear();
}
public bool Contains(object item)
{
// maybe check if T is of the desired type
return collection.Contains((T)item);
}
public void CopyTo(object[] array, int arrayIndex)
{
// maybe check if T is of the desired type
collection.CopyTo(array.Cast<T>().ToArray(), arrayIndex);
}
public int Count
{
get { return collection.Count; }
}
public bool IsReadOnly
{
get { return collection.IsReadOnly; }
}
public bool Remove(object item)
{
// maybe check if T is of the desired type
return collection.Remove((T)item);
}
public IEnumerator<object> GetEnumerator()
{
yield return collection;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return collection.GetEnumerator();
}
}
Instead of
EntityCollection<MyNamespace.Models.MyEntityClass> collection = ...;
ICollection<Object> generic = collection ;
you would have to write:
EntityCollection<MyNamespace.Models.MyEntityClass> collection = ...;
ICollection<Object> generic = new Wrapper(collection);
And could adjust the wrapper class at the points marked by comments how to deal with type problems.
Since ICollection<T> hasn't variance, ICollection<MyEntityClass> and ICollection<object> are different types, unrelated to each other.
I'm trying to do this in a method that generally can add and remove
items from what might be an EntityCollection or some other IList or
ISet
So, why don't you work with IList? Looks like you don't care about real type of items in this method.
I noticed something strange and there is a possibility I am wrong.
I have an interface IA and class A:
interface IA { .... }
class A : IA { .... }
In other class I have this:
private IList<A> AList;
public IList<IA> {
get { return AList; }
}
But I get compilation error.
But if I change it to:
public IList<IA> {
get { return AList.ToArray(); }
}
Everything is fine.
Why is it?
Why this doesn't work
private IList<A> AList;
public IList<IA> { get { return AList; } }
Exposing the property as IList<IA> would allow you to try to add class B : IA to the list, but the underlying list is really IList<A>, B is not A, so this would blow up in your face. Thus, it is not allowed.
Why this works:
public IList<IA> { get { return AList.ToArray(); } }
Array variance is broken. You can return the list as an array, it will still blow up in your face at runtime if you tried an Add operation (or try to replace an object at a given index with something other than an object of type A, but it's legal at compile time. A different example of this variance at play:
string[] array = new string[10];
object[] objs = array; // legal
objs[0] = new Foo(); // will bite you at runtime
From comments:
So what you suggest to use? How can I make the property return valid
object? How can I make the return value read only?
If consumers only need to iterate over the sequence and not have random, indexed access to it, you can expose the property as an IEnumerable<IA>.
public IEnumerable<IA> TheList
{
get { return AList.Select(a => a); }
}
(The Select is actually not technically needed, but using this will prevent consumers from being able to cast the result to its true underlying List<> type.) If the consumers decide they want a list or an array, they are free to call ToList() or ToArray() on it, and whatever they do with it (in terms of adding, removing, replacing items) will not affect your list. (Changes to the items' properties would be visible.) Similarly, you could also expose the collection an IList<IA> yourself in a safe way
public IList<IA> TheList
{
get { return AList.ToList<IA>(); }
}
Again, this would return a copy of the list, so any changes to it would not affect your underlying list.
Because native arrays are broken. This code is bad, you shouldn't do it, and the C# designers wish desperately they could undo it.
Arrays are covariant but lists are not.
I have a class which has two HashSet<String> collections as private members. Other classes in my code would like to be able to iterate over those HashSets and read their contents. I don't want to write a standard getter because another class could still do something like myClass.getHashSet().Clear(); Is there any other way to expose the elements of my HashSets to iteration without exposing the reference to the HashSet itself? I'd love to be able to do this in a way that is compatible with for-each loops.
Assuming you're using .NET 3.5, one alternative to writing the yield code yourself is to call a LINQ method. For example:
public IEnumerable<string> HashSet
{
get { return privateMember.Select(x => x); }
}
or
public IEnumerable<string> HashSet
{
get { return privateMember.Skip(0); }
}
There are various LINQ operators which could be used like this - using Skip(0) is probably the most efficient, as after the initial "skip 0 values" loop, it's probably just the foreach/yield return loop shown in the other answers. The Select version will call the no-op projection delegate for each item yielded. The chances of this difference being significant are astronomically small, however - I suggest you go with whatever makes the code clearest to you.
Expose a IEnumerable<T> property:
public IEnumerable<whatevertype> MyHashSet {
get {
return this.myHashSet;
}
}
Of course, the user of this code can cast that IEnumerable<T> to a HashSet<T> and edit elements, so to be on the safe side (while hurting performance), you can do:
public IEnumerable<whatevertype> MyHashSet {
get {
return this.myHashSet.ToArray();
}
}
or:
public IEnumerable<whatevertype> MyHashSet {
get {
foreach(var item in this.myHashSet) {
yield return item;
}
}
}
A more performant method of protection, but less convenient to the caller, is to return an IEnumerator<T>:
public IEnumerator<whatevertype> GetMyHashSetEnumerator() {
return this.myHashSet.GetEnumerator();
}
Add a method/property like this to avoid exposing the actual container:
public IEnumerable EnumerateFirst()
{
foreach( var item in hashSet )
yield return item;
}
You can also use the Select method to create a wrapper than can't be cast back to HashSet<T>:
public IEnumerable<int> Values
{
get { return _values.Select(value => value);
}
This avoids iterating over _values twice, as you would with .ToArray(), but keeps the implementation to a single clean line.
You may also provide a sequence like this:
public IEnumerable<string> GetHashSetOneValues()
{
foreach (string value in hashSetOne)
yield return value;
}
This method may then be called within a foreach loop:
foreach (string value in myObject.GetHashSetOneValues())
DoSomething(value);
This might be quite a bit too late to the party but the easiest way today would be to use Linq. Instead of writing
public IEnumerable<string> GetValues()
{
foreach(var elem in list)
yield return elem;
}
you can write
public IEnumerable<string> GetValues() => list;
Make your getter expose the HashSet as IEnumerable.
private HashSet<string> _mine;
public IEnumerable<string> Yours
{
get { return _mine; }
}
If the generic type is mutable, then that can still be modified, but no items can be added or removed from your HashSet.