List<T>.Enumerator IEnumerator.Reset() method implementation - c#

Despite the fact, that IEnumerator.Reset method should never be used I found strange behavior of the method implementation within List<T>.
No matter how you examine the .NET Framework Source Code (tried with reference source and ILSpy) the method is implemented as following:
void System.Collections.IEnumerator.Reset() {
if (version != list._version) {
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
index = 0;
current = default(T);
}
However, it looks like the method is never called at all! Consider the code:
var list = new List<int>(1) { 3 };
using (var e = list.GetEnumerator())
{
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
((IEnumerator)e).Reset();
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
}
It's pretty clear, that it should print True and 3 twice. Instead of that the result is
True
3
False
0
Any simple explanation I'm missing?

Any simple explanation I'm missing?
Yes: you're boxing the List.Enumerator here:
((IEnumerator)e).Reset();
That takes a copy of the existing one and resets it - leaving the original in one piece.
To reset the actual enumerator, you'd need something like this:
var list = new List<int>(1) { 3 };
var e = list.GetEnumerator();
// Can't use "ref" with a using statement
try
{
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
Reset(ref e);
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
}
finally
{
e.Dispose();
}
static void Reset<T>(ref T enumerator) where T : IEnumerator
{
enumerator.Reset();
}
It's tricky because it uses explicit interface implementation.
I haven't tested it, but I think that should work for you. Obviously it's a bad idea to do this...
EDIT: Alternatively, just change your variable type to IEnumerator or IEnumerator<int> to start with. Then it will be boxed once, and the Reset method will mutate the boxed value:
var list = new List<int>(1) { 3 };
using (IEnumerator e = list.GetEnumerator())
{
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
e.Reset();
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
}

Related

C# best practice: "break" from within Action<> callback called in a loop?

I had to write my own foreach method for various reasons. This resembles an IEnumerable foreach statement:
public void ForEachEdge(in Vertex vertex, Action<Edge> callback)
{
var edge = GetEdge(vertex.BaseEdgeIndex);
do
{
callback.Invoke(edge);
edge = GetEdge(edge.GetNext(vertex.Index));
} while (edge.Index != vertex.BaseEdgeIndex);
}
I'm using it like so but I wish to be able to "break" out of the entire loop:
ForEachEdge(edge.Vertex0Index, (e) =>
{
if (inEdge.AreConnectingSameVertices(e))
{
// break out of inner while loop here ...
}
});
What would be best practice to break?
Return a status value?
Pass a "ref bool stopEnumerating" parameter in? (requires class instance to wrap it in, right?)
Your thoughts ...
I'm mostly concerned about what end users (developers) would expect in such a case.
the ref parameter method won't be as clean as a return value indicating continuation status. You would have to switch to a Func<Edge, bool>
Func<Edge, bool> callback;
...
if (callback.Invoke(edge)) {
/// do your break logic
}
I decided that (for now) I'll go with a Predicate<> rather than Action<>:
public void ForEachEdge(in Vertex vertex, Predicate<Edge> callback)
{
var edge = GetEdge(vertex.BaseEdgeIndex);
do
{
if (callback.Invoke(edge))
break;
edge = GetEdge(edge.GetNextRadialEdgeIndex(vertex.Index));
} while (edge.IsValid && edge.Index != vertex.BaseEdgeIndex);
}
Which makes the user's code look like this:
ForEachEdge(edge.Vertex0Index, e =>
{
if (inEdge.AreConnectingSameVertices(e))
{
// found it, do something, then exit loop
return true;
}
// continue with next item
return false;
});
The nicest thing about this solution: both Predicate<> and Action<> variants can exist side-by-side! User either returns true/false from the predicate, or does not return anything and thus uses the Action<> version, like so:
ForEachEdge(edge.Vertex0Index, e =>
{
if (inEdge.AreConnectingSameVertices(e))
{
// do stuff
}
});
Purrfect! :)

Iterator function for IDisposable items

Suppose I want to create an iterator function that yields IDisposable items.
IEnumerable<Disposable> GetItems()
{
yield return new Disposable();
yield return new Disposable();
}
This does not seem ideal for the client code:
foreach (var item in source.GetItems())
{
using (item)
{
// ...
}
}
Intuitively, the using comes too late. Things could get moved around. One could accidentally insert code between the foreach and the using. Not ideal.
I am looking for a better alternative!
One approach that comes to mind is creating the following API instead of an iterator function:
// Client
while (source.HasItem)
{
using (var item = source.GetNextItem())
{
// ...
}
}
// Source
private IEnumerator<Disposable> Enumerator { get; }
private bool? _hasItem;
bool HasItem
{
get
{
if (this._hasItem == null) this._hasItem = this.Enumerator.MoveNext();
return this._hasItem;
}
}
Disposable GetNextItem()
{
if (!this.HasItem) throw new IndexOutOfBoundsException();
this._hasItem = null;
return this.Enumerator.Current;
}
But now it seems that the source has to become IDisposable! How else would it know when to dispose Enumerator? That can be an unpleasant side-effect.
I am looking for an alternative that feels solid in the client, but that keeps the source from becoming IDisposable too.
Edit - Clarification: I forgot to mention that some of the content that we need comes from an iterator. Concretely, imagine that we are returning IDbCommand instances, which are IDisposable. Before returning each command, we need to populate it with some query data, which in turn comes from a simple iterator method.
If I understand correctly, the following pattern works for you
foreach (var item in source.GetItems())
{
using (item)
{
// ...
}
}
but the potential problem is putting some code outside the using block. So why don't you just wrap that logic in a custom extensions method:
public static class EnumerableExtennisons
{
public static IEnumerable<T> WithUsing<T>(this IEnumerable<T> source)
where T : IDisposable
{
foreach (var item in source)
{
using (item)
yield return item;
}
}
}
This way you ensure the item is wrapped in using block *before** returning it to the caller, so there is no way the caller to insert code before/after it. The C# compiler generated code ensures the item.Dispose is called in either MoveNext or Dispose method of the IEnumerator<T> (in case the iteration ends earlier).
The usage would be to append .WithUsing() call instead of using block where needed:
foreach (var item in source.GetItems().WithUsing())
{
// ...
}
We can expose only an IEnumerator<T>, which supports nothing but MoveNext() and Current.
Now, the underlying, private iterator function can be streaming, taking care of disposing the items. No invalid operations are introduced to the client - unless they try to store the borrowed objects and try to use them later, where it becomes clear that the objects are already disposed.
// Client
using (var itemEnumerator = source.GetItemEnumerator())
{
while (itemEnumerator.MoveNext())
var current = itemEnumerator.Current;
}
// Source
IEnumerator<Disposable> GetItemEnumerator() => this.StreamItems().GetEnumerator();
private IEnumerable<Disposable> StreamItems()
{
while (this.ShouldCreateItem())
{
using (var item = this.CreateItem())
{
yield return item;
}
}
}
The iterator function itself can take responsibility for placing a using (i.e. disposing the current item when the next is requested).
IEnumerable<Disposable> GetItems()
{
// Assumming CreateItems() is an iterator as well
foreach (var item in this.CreateItems())
using (item) yield return item;
}
As a result, we will essentially have a streaming-only iterator. Methods like ToList() become meaningless, because only one item is usable at a time.
Unfortunately, this does create room for error.

How can I delete several items from an object, which is copy of another object, without affecting the one of which is derived?

help me please to use the function "RemoveAll" or maybe there should be another implementation.
I have an object (services) which contains a list with items.
I make another object (anotherService ) which is equal with the first.
I should remove from second object (anotherService) items which have mainService == false.
I use the "RemoveAll" function, but after this action is made, from the object (services) items which are mainService = false are also removed.
I need to have the first object completed how it was before removing.
var services = DictionaryObject.GetDictionaryValidatedByDate<ServiceInfo>(DictionaryType.REF_SERVICE, DateTime.Now);
var anotherService = services;
anotherService.RemoveAll(p =>
{
if (p.Model.mainService == false)
{
return true;
}
return false;
});
Thank you all.
The line:
var anotherService = services;
simply defines a new variable and assigns the existing value (almost certainly a class reference) to that variable; no new object is created. Any member-access on a reference is going to go to the same actual object, no matter which variable you use (there is only one object).
To do what you need, you would need to create a shallow or deep clone (depending on what exactly you want to happen).
A shallow clone is pretty easy to do by manually adding a Clone() method or similar (maybe ICloneable) which copies the properties (noting that in the case of lists, a new list with the same data is usually created). A deep clone is trickier - a common cheat there is to serialize and deserialize the item.
The Serialization approach can be found here in this answer :
For reference I have posted it here.
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T) formatter.Deserialize(ms);
}
}
Your problem is that you are changing the same object, just through a different reference. you need to make sure that you removes items from a different object, which contains copies of the same information. There are a few ways you could do this. The simplest is to just create 2 objects:
var services = DictionaryObject.GetDictionaryValidatedByDate<ServiceInfo>(DictionaryType.REF_SERVICE, DateTime.Now);
var anotherService = DictionaryObject.GetDictionaryValidatedByDate<ServiceInfo>(DictionaryType.REF_SERVICE, DateTime.Now);;
anotherService.RemoveAll(p =>
{
if (p.Model.mainService == false || p.Model.mainService == true)
{
return true;
}
return false;
});
or you could copy/clone your object something like:
var anotherService = services.Copy(); //or maybe use a copy constructor here instead:
// var anotherService = new ServiceInfo(sevices);
anotherService.RemoveAll(p =>
{
if (p.Model.mainService == false || p.Model.mainService == true)
{
return true;
}
return false;
});
When you implement the Copy() method or the constructor which takes the object to copy you need to make sure that you create copies of dictionaries and do not just use references to the same dictionary.
if your object being returned is just an IDictionary<K,V> (its not clear from the code provided) you may be able to do this:
var anotherService = new Dictionary<KeyType,ValueType>(services)
anotherService.RemoveAll(p =>
{
if (p.Model.mainService == false || p.Model.mainService == true)
{
return true;
}
return false;
});

iSynaptic.Commons and the Maybe Monad

I've been trying to figure out how I could use the Maybe monad in iSynaptic.Commons in a context where my value retriever could throw an exception:
For example:
dynamic expando = new Expando();
expando.Name = "John Doe";
var maybe = Maybe.Defer(()=>(string)expando.NonExistingProperty);
//In this context I would like the exception which is thrown
//to result in Maybe<string>.NoValue;
if(maybe.HasValue) {
//Do something
}
Is this possible with the implementation of maybe that is out there
There are several ways of using iSynaptic.Commons to allow an exception. Each way I found requires the .Catch() extension method to let the monad know to silently catch the exception. Also, be careful when accessing the property maybe.Value. If this property is Maybe.NoValue, an InvalidOperationException will be thrown.
1) Create a "OnExceptionNoValue" extension method. This will check the Maybe to see if it has an exception. If it does, a NoValue Maybe will be returned. Otherwise the original Maybe will be returned.
public static class MaybeLocalExtensions
{
public static Maybe<T> OnExceptionNoValue<T>(this Maybe<T> maybe)
{
return maybe.Exception != null ? Maybe<T>.NoValue : maybe;
}
}
// Sample Use Case:
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch()
.OnExceptionNoValue();
2) Create a "BindCatch" extension method. This changes the behavior of the normal bind when an exception is present to return Maybe.NoValue instead of throwing an exception.
public static class MaybeLocalExtensions
{
public static Maybe<TResult> BindCatch<T, TResult>(this Maybe<T> #this, Func<T, Maybe<TResult>> selector)
{
var self = #this;
return new Maybe<TResult>(() => {
if (self.Exception != null)
return Maybe<TResult>.NoValue;
return self.HasValue ? selector(self.Value) : Maybe<TResult>.NoValue;
});
}
}
// Sample Use Case:
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch()
.BindCatch(m => m.ToMaybe());
3) This way also uses the Catch() extension method, but uses the maybe.HasValue property instead of relying on extension methods. If an exception is present in the Maybe, the HasValue property is false. When this value is false, the Maybe.NoValue can replace the value of the variable maybe or whatever needs to be done in this case.
dynamic expando = new ExpandoObject();
expando.Name = "John Doe";
// This example falls to the else block.
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch();
//In this context I would like the exception which is thrown
//to result in Maybe<string>.NoValue;
if (maybe.HasValue) {
//Do something
Console.WriteLine(maybe.Value);
} else {
maybe = Maybe<string>.NoValue; // This line is run
}
// This example uses the if block.
maybe = Maybe.Defer(() => (string)expando.Name).Catch();
//to result in Maybe<string>.NoValue;
if (maybe.HasValue) {
//Do something
Console.WriteLine(maybe.Value); //This line is run
} else {
maybe = Maybe<string>.NoValue;
}
These answers are all variations on the same theme, but I hope they are helpful.

Different behaviors with a for loop and a foreach loop with closures

I can't explain an issue I've run across. Basically I get a different answer if I use lambda syntax in a foreach loop than if I use it in a for loop. In the code below I register a delegate in a "dispatcher" class. I then later wrap the delegate on the way out in another delegate and return a list of these wrapped delegates. I then execute them. The expected output of executing the wrapped function list is 1,2. However I don't see that when I combine a lambda and a foreach loop.
This is not the code that is causing the problem, but the simplest case I could make to reproduce it. I would prefer not to discuss use cases of this, I'm more curious as to why I get behavior I'm not expecting. If I use the foreach loop below with the lambda syntax it fails. If I use the new Action() syntax and a foreach it works, if I use the lambda syntax in a for loop it works. Can anyone explain what is going on here. This has me really stumped.
public class Holder
{
public Holder(int ID, Dispatcher disp)
{
this.ID = ID;
disp.Register(Something);
}
public int ID { get; set; }
private void Something(int test) { Console.WriteLine(ID.ToString()); }
}
public class Dispatcher
{
List<Action<int>> m_Holder = new List<Action<int>>();
public void Register(Action<int> func)
{
m_Holder.Add(func);
}
public List<Action<int>> ReturnWrappedList()
{
List<Action<int>> temp = new List<Action<int>>();
//for (int i = 0; i < m_Holder.Count; i++) //Works - gives 1, 2
//{
// var action = m_Holder[i];
// temp.Add(p => action(p));
//}
foreach (var action in m_Holder)
{
temp.Add(p => action(p)); //Fails - gives 2,2
//temp.Add(new Action<int>(action)); Works - gives 1,2
}
return temp;
}
}
class Program
{
static void Main(string[] args)
{
var disp = new Dispatcher();
var hold1 = new Holder(1, disp);
var hold2 = new Holder(2, disp);
disp.ReturnWrappedList().ForEach(p => p(1));
}
}
This is the infamous "closing over the loop variable" gotcha.
Closing over the loop variable considered harmful (and part two)
Have you tried:
foreach (var action in m_Holder)
{
var a = action;
temp.Add(p => a(p));
}
This is the classic issue of a captured closure with a scope that isn't what you expect. In the foreach, the action has outer scope, so the execution captures the last value of the loop. In the for case, you create the action in inner scope, so the closure is over the local value at each iteration.

Categories

Resources