Take this pseudo example code:
static System.Runtime.InteropServices.ComTypes.IEnumString GetUnmanagedObject() => null;
static IEnumerable<string> ProduceStrings()
{
System.Runtime.InteropServices.ComTypes.IEnumString obj = GetUnmanagedObject();
var result = new string[1];
var pFetched = Marshal.AllocHGlobal(sizeof(int));
while(obj.Next(1, result, pFetched) == 0)
{
yield return result[0];
}
Marshal.ReleaseComObject(obj);
}
static void Consumer()
{
foreach (var item in ProduceStrings())
{
if (item.StartsWith("foo"))
return;
}
}
Question is if i decide to not enumerate all values, how can i inform producer to do cleanup?
Even if you are after a solution using yield return, it might be useful to see how this can be accomplished with an explicit IEnumerator<string> implementation.
IEnumerator<T> derives from IDisposable and the Dispose() method will be called when foreach is left (at least since .NET 1.2, see here)
static IEnumerable<string> ProduceStrings()
{
return new ProduceStringsImpl();
}
This is the class implementing IEnumerable<string>
class ProduceStringsImpl : IEnumerable<string>
{
public IEnumerator<string> GetEnumerator()
{
return new EnumProduceStrings();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And here we have the core of the solution, the IEnumerator<string> implementation:
class EnumProduceStrings : IEnumerator<string>
{
private System.Runtime.InteropServices.ComTypes.IEnumString _obj;
private string[] _result;
private IntPtr _pFetched;
public EnumProduceStrings()
{
_obj = GetUnmanagedObject();
_result = new string[1];
_pFetched = Marshal.AllocHGlobal(sizeof(int));
}
public bool MoveNext()
{
return _obj.Next(1, _result, _pFetched) == 0;
}
public string Current => _result[0];
void IEnumerator.Reset() => throw new NotImplementedException();
object IEnumerator.Current => Current;
public void Dispose()
{
Marshal.ReleaseComObject(_obj);
Marshal.FreeHGlobal(_pFetched);
}
}
I knew i can! Despite guard, Cancel is called only one time in all circumtances.
You can instead encapsulate logic with a type like IterationResult<T> and provide Cleanup method on it but its essentially same idea.
public class IterationCanceller
{
Action m_OnCancel;
public bool Cancelled { get; private set; }
public IterationCanceller(Action onCancel)
{
m_OnCancel = onCancel;
}
public void Cancel()
{
if (!Cancelled)
{
Cancelled = true;
m_OnCancel();
}
}
}
static IEnumerable<(string Result, IterationCanceller Canceller)> ProduceStrings()
{
var pUnmanaged = Marshal.AllocHGlobal(sizeof(int));
IterationCanceller canceller = new IterationCanceller(() =>
{
Marshal.FreeHGlobal(pUnmanaged);
});
for (int i = 0; i < 2; i++) // also try i < 0, 1
{
yield return (i.ToString(), canceller);
}
canceller.Cancel();
}
static void Consumer()
{
foreach (var (item, canceller) in ProduceStrings())
{
if(item.StartsWith("1")) // also try consuming all values
{
canceller.Cancel();
break;
}
}
}
public class Obj: ReactiveObject {
public Obj() {
this.WhenPropertyChanged(n => n.Prop)
.Subscribe(o =>
{
Foo();
});
this.ObservableForProperty(n => n.Prop)
.Subscribe(o =>
{
Foo2();
});
}
private bool _prop;
public bool Prop { get => _prop; set => this.RaiseAndSetIfChanged(ref _prop, value); }
public void Foo() {}
public void Foo2() {}
}
Both of these methods return IObservable<Obj, bool>. Description of both methods says that they observer property changes, yet only second reacts for changes (Foo2 is called).
What is difference between these methods and when they should be used? Documentation on https://www.reactiveui.net/ seesm to be outdated.
I need to retry a certain method until it returns a non-empty Guid.
There's an awesome answer that retries based on whether there is an exception; however, I would like to generalize this class to be able to handle any specified condition.
The current usage will perform an action a specific number of times until there are no exceptions:
Retry.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1));
or:
Retry.Do(SomeFunctionThatCanFail, TimeSpan.FromSeconds(1));
or:
int result = Retry.Do(SomeFunctionWhichReturnsInt, TimeSpan.FromSeconds(1), 4);
How can I modify this class such that it retries based on the return value of the function that I pass in?
For example, If I wanted to retry until my function returned 3:
Retry.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1)).Until(3);
Which would mean execute SomeFunctionThatCanFail(), every 1 second, until SomeFunctionThatCanFail() = 3?
How would I generalize the usage of Retry.Do until a condition is met?
public static class Retry
{
public static void Do(
Action action,
TimeSpan retryInterval,
int retryCount = 3)
{
Do<object>(() =>
{
action();
return null;
}, retryInterval, retryCount);
}
public static T Do<T>(
Func<T> action,
TimeSpan retryInterval,
int retryCount = 3)
{
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++) //I would like to change this logic so that it will retry not based on whether there is an exception but based on the return value of Action
{
try
{
if (retry > 0)
Thread.Sleep(retryInterval);
return action();
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
How about creating the following interface:
public interface IRetryCondition<TResult>
{
TResult Until(Func<TResult, bool> condition);
}
public class RetryCondition<TResult> : IRetryCondition<TResult>
{
private TResult _value;
private Func<IRetryCondition<TResult>> _retry;
public RetryCondition(TResult value, Func<IRetryCondition<TResult>> retry)
{
_value = value;
_retry = retry;
}
public TResult Until(Func<TResult, bool> condition)
{
return condition(_value) ? _value : _retry().Until(condition);
}
}
And then, you'll update your Retry static class:
public static class Retry
{
// This method stays the same
// Returning an IRetryCondition does not make sense in a "void" action
public static void Do(
Action action,
TimeSpan retryInterval,
int retryCount = 3)
{
Do<object>(() =>
{
action();
return null;
}, retryInterval, retryCount);
}
// Return an IRetryCondition<T> instance
public static IRetryCondition<T> Do<T>(
Func<T> action,
TimeSpan retryInterval,
int retryCount = 3)
{
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
if (retry > 0)
Thread.Sleep(retryInterval);
// We return a retry condition loaded with the return value of action() and telling it to execute this same method again if condition is not met.
return new RetryCondition<T>(action(), () => Do(action, retryInterval, retryCount));
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
You'll be able to achieve something like the following:
int result = Retry.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1)).Until(r => r == 3);
A more functional approach
I tried to come up with a more "functional oriented" solution (somewhat similar to LINQ):
First, we would have two interfaces for executing the action:
public interface IRetryResult
{
void Execute();
}
public interface IRetryResult<out TResult>
{
TResult Execute();
}
Then, we'll need two interfaces for configuring the retry operation:
public interface IRetryConfiguration : IRetryResult
{
IRetryConfiguration Times(int times);
IRetryConfiguration Interval(TimeSpan interval);
}
public interface IRetryConfiguration<out TResult> : IRetryResult<TResult>
{
IRetryConfiguration<TResult> Times(int times);
IRetryConfiguration<TResult> Interval(TimeSpan interval);
IRetryConfiguration<TResult> Until(Function<TResult, bool> condition);
}
Finally, we'll need two implementations for both interfaces:
public class ActionRetryConfiguration : IRetryConfiguration
{
private readonly Action _action;
private readonly int? _times;
private readonly TimeSpan? _interval;
public ActionRetryConfiguration(Action action, int? times, TimeSpan? interval)
{
_action = action;
_times = times;
_interval = interval;
}
public void Execute()
{
Execute(_action, _times, _interval);
}
private void Execute(Action action, int? times, TimeSpan? interval)
{
action();
if (times.HasValue && times.Value <= 1) return;
if (times.HasValue && interval.HasValue) Thread.Sleep(interval.Value);
Execute(action, times - 1, interval);
}
public IRetryConfiguration Times(int times)
{
return new ActionRetryConfiguration(_action, times, _interval);
}
public IRetryConfiguration Interval(TimeSpan interval)
{
return new ActionRetryConfiguration(_action, _times, interval);
}
}
public class FunctionRetryConfiguration<TResult> : IRetryConfiguration<TResult>
{
private readonly Func<TResult> _function;
private readonly int? _times;
private readonly TimeSpan? _interval;
private readonly Func<TResult, bool> _condition;
public FunctionRetryConfiguration(Func<TResult> function, int? times, TimeSpan? interval, Func<TResult, bool> condition)
{
_function = function;
_times = times;
_interval = interval;
_condition = condition;
}
public TResult Execute()
{
return Execute(_function, _times, _interval, _condition);
}
private TResult Execute(Func<TResult> function, int? times, TimeSpan? interval, Func<TResult, bool> condition)
{
TResult result = function();
if (condition != null && condition(result)) return result;
if (times.HasValue && times.Value <= 1) return result;
if ((times.HasValue || condition != null) && interval.HasValue) Thread.Sleep(interval.Value);
return Execute(function, times - 1, interval, condition);
}
public IRetryConfiguration<TResult> Times(int times)
{
return new FunctionRetryConfiguration<TResult>(_function, times, _interval, _condition);
}
public IRetryConfiguration<TResult> Interval(TimeSpan interval)
{
return new FunctionRetryConfiguration<TResult>(_function, _times, interval, _condition);
}
public IRetryConfiguration<TResult> Until(Func<TResult, bool> condition)
{
return new FunctionRetryConfiguration<TResult>(_function, _times, _interval, condition);
}
}
And, lastly, the Retry static class, the entry point:
public static class Retry
{
public static IRetryConfiguration Do(Action action)
{
return new ActionRetryConfiguration(action, 1, null);
}
public static IRetryConfiguration<TResult> Do<TResult>(Func<TResult> action)
{
return new FunctionRetryConfiguration<TResult>(action, 1, null, null);
}
}
I think this approach is less buggy, and cleaner.
Also, it let you do things like these:
int result = Retry.Do(SomeIntMethod).Interval(TimeSpan.FromSeconds(1)).Until(n => n > 20).Execute();
Retry.Do(SomeVoidMethod).Times(4).Execute();
Well, if I understood everything correctly, something like this should solve your problem:
public static T Do<T>(Func<T> action, TimeSpan retryInterval, Predicate<T> predicate)
{
var exceptions = new List<Exception>();
try
{
bool succeeded;
T result;
do
{
result = action();
succeeded = predicate(result);
} while (!succeeded);
return result;
}
catch (Exception ex)
{
exceptions.Add(ex);
}
throw new AggregateException(exceptions);
}
Add this method to your retry class.
I've tried it with a sample ConsoleApplication, with this code:
class Program
{
static void Main(string[] args)
{
var _random = new Random();
Func<int> func = () =>
{
var result = _random.Next(10);
Console.WriteLine(result);
return result;
};
Retry.Do(func, TimeSpan.FromSeconds(1), i => i == 5);
Console.ReadLine();
}
}
And indeed, it stops when it randoms 5.
Microsoft's Reactive Framework (NuGet "Rx-Main") has all of the operators already built to do this kind of thing out of the box.
Try this:
IObservable<int> query =
Observable
.Defer(() =>
Observable.Start(() => GetSomeValue()))
.Where(x => x == 1)
.Timeout(TimeSpan.FromSeconds(0.1))
.Retry()
.Take(1);
query
.Subscribe(x =>
{
// Can only be a `1` if produced in less than 0.1 seconds
Console.WriteLine(x);
});
It seems like you're overthinking this:
int returnValue = -1;
while (returnValue != 3)
{
returnValue = DoStuff();
// DoStuff should include a step to avoid maxing out cpu
}
return returnValue;
Of course, "3" could be a variable that you pass into the function.
I'm having some hard time understanding the Subject object.
Consider the following code:
var sub = new Subject<int>();
sub.Subscribe(x => Console.WriteLine(x)); //subscriber #1
sub.Subscribe(x => Console.WriteLine(x)); //subscriber #2
sub.OnNext(2);
I'm creating a subject of int, and when i execute OnNext it calls the other subscribers (#1 and #2).
The thing that i don't get is that i read that Subject means an object which is both observable and observer but how does this explains why when i call OnNext the other subscribers are called.
I would understand if OnNext of the subject would propagate it to all subscribers = publish to all others (which make sense) but when I checked the source code i couldn't see anything that does it, see below.
Can someone maybe understand from the code below what exactly makes the OnNext(2) propagate to the other subscriptions? (#1, #2)?
public sealed class Subject : ISubject, ISubject, IObserver, IObservable, IDisposable
{
// Fields
private volatile IObserver _observer;
// Methods
public Subject()
{
this._observer = NopObserver<T>.Instance;
}
public void Dispose()
{
this._observer = DisposedObserver<T>.Instance;
}
public void OnCompleted()
{
IObserver<T> comparand = null;
IObserver<T> completed = DoneObserver<T>.Completed;
do
{
comparand = this._observer;
}
while (((comparand != DisposedObserver<T>.Instance) && !(comparand is DoneObserver<T>)) && (Interlocked.CompareExchange<IObserver<T>>(ref this._observer, completed, comparand) != comparand));
comparand.OnCompleted();
}
public void OnError(Exception error)
{
if (error == null)
{
throw new ArgumentNullException("error");
}
IObserver<T> comparand = null;
DoneObserver<T> observer3 = new DoneObserver<T> {
Exception = error
};
DoneObserver<T> observer2 = observer3;
do
{
comparand = this._observer;
}
while (((comparand != DisposedObserver<T>.Instance) && !(comparand is DoneObserver<T>)) && (Interlocked.CompareExchange<IObserver<T>>(ref this._observer, observer2, comparand) != comparand));
comparand.OnError(error);
}
public void OnNext(T value)
{
this._observer.OnNext(value);
}
public IDisposable Subscribe(IObserver<T> observer)
{
if (observer == null)
{
throw new ArgumentNullException("observer");
}
IObserver<T> comparand = null;
IObserver<T> observer3 = null;
do
{
comparand = this._observer;
if (comparand == DisposedObserver<T>.Instance)
{
throw new ObjectDisposedException("");
}
if (comparand == DoneObserver<T>.Completed)
{
observer.OnCompleted();
return Disposable.Empty;
}
DoneObserver<T> observer4 = comparand as DoneObserver<T>;
if (observer4 != null)
{
observer.OnError(observer4.Exception);
return Disposable.Empty;
}
if (comparand == NopObserver<T>.Instance)
{
observer3 = observer;
}
else
{
Observer<T> observer5 = comparand as Observer<T>;
if (observer5 != null)
{
observer3 = observer5.Add(observer);
}
else
{
observer3 = new Observer<T>(new ImmutableList<IObserver<T>>(new IObserver<T>[] { comparand, observer }));
}
}
}
while (Interlocked.CompareExchange<IObserver<T>>(ref this._observer, observer3, comparand) != comparand);
return new Subscription<T>((Subject<T>) this, observer);
}
private void Unsubscribe(IObserver<T> observer)
{
IObserver<T> comparand = null;
IObserver<T> instance = null;
Label_0004:
comparand = this._observer;
if ((comparand != DisposedObserver<T>.Instance) && !(comparand is DoneObserver<T>))
{
Observer<T> observer4 = comparand as Observer<T>;
if (observer4 != null)
{
instance = observer4.Remove(observer);
}
else
{
if (comparand != observer)
{
return;
}
instance = NopObserver<T>.Instance;
}
if (Interlocked.CompareExchange<IObserver<T>>(ref this._observer, instance, comparand) != comparand)
{
goto Label_0004;
}
}
}
// Properties
public bool HasObservers
{
get
{
return (((this._observer != NopObserver<T>.Instance) && !(this._observer is DoneObserver<T>)) && (this._observer != DisposedObserver<T>.Instance));
}
}
// Nested Types
private class Subscription : IDisposable
{
// Fields
private IObserver<T> _observer;
private Subject<T> _subject;
// Methods
public Subscription(Subject<T> subject, IObserver<T> observer)
{
this._subject = subject;
this._observer = observer;
}
public void Dispose()
{
IObserver<T> observer = Interlocked.Exchange<IObserver<T>>(ref this._observer, null);
if (observer != null)
{
this._subject.Unsubscribe(observer);
this._subject = null;
}
}
}
}
I know that but what bothers me is that it didn't make sense. I dug further into the code and found out that their internal implementation of observer contains more observers, see below.
And if you check the OnNext method you can see that they are iterating over all the observers and calling their OnNext method.
Now everything make sense to me, i understood the logic but couldn't see where it was implemented.
internal class Observer<T> : IObserver<T>
{
private readonly ImmutableList<IObserver<T>> _observers;
public Observer(ImmutableList<IObserver<T>> observers)
{
this._observers = observers;
}
internal IObserver<T> Add(IObserver<T> observer)
{
return new Observer<T>(this._observers.Add(observer));
}
public void OnCompleted()
{
foreach (IObserver<T> observer in this._observers.Data)
{
observer.OnCompleted();
}
}
public void OnError(Exception error)
{
foreach (IObserver<T> observer in this._observers.Data)
{
observer.OnError(error);
}
}
public void OnNext(T value)
{
foreach (IObserver<T> observer in this._observers.Data)
{
observer.OnNext(value);
}
}
internal IObserver<T> Remove(IObserver<T> observer)
{
int index = Array.IndexOf<IObserver<T>>(this._observers.Data, observer);
if (index < 0)
{
return this;
}
if (this._observers.Data.Length == 2)
{
return this._observers.Data[1 - index];
}
return new Observer<T>(this._observers.Remove(observer));
}
}
Subject is an observable because you can subscribe to it. You do it in your example (you did subscribe two subscribers).
Subject is also an observer because you can do the following:
someObservable.Subscribe(subject);
That way your subject will receive the events from someObservable and propagate them to its own subscribers.
P.S. in your code you called the OnNext() method yourself. But that is exactly what will someObservable do when you subscribe to it with your subject.
I have such a class:
public static class CacheManager
{
static object lockObject = new object();
static MemcachedClient CacheObject
{
get
{
if (!MemcachedClient.Exists(Settings.Default
.CacheInstanceName))
{
MemcachedClient.Setup(Settings.Default
.CacheInstanceName,
new string[] {Settings.Default
.CacheHostAddress});
}
//
//
return MemcachedClient.GetInstance(Settings
.Default.CacheInstanceName);
}
}
public static List<TData> Get<TData>(string key, Func<List<int>> getListCallback,
Func<int, TData> getItemCallback) where TData : class
{
var result = new List<TData>();
//
//
var list = CacheObject.Get(key);
if (list == null)
{
lock (lockObject)
{
list = CacheObject.Get(key);
if (list == null)
{
list = getListCallback();
CacheObject.Set(key, list);
//
//
foreach (var id in (List<int>)list)
{
var item = getItemCallback(id);
result.Add(item);
CacheObject.Set(string.Concat(key, id), item);
}
}
}
}
else
{
foreach (var id in (List<int>)list)
{
var itemKey = string.Concat(key, id);
//
//
var item = CacheObject.Get(itemKey);
if (item == null)
{
lock (lockObject)
{
item = CacheObject.Get(itemKey);
if (item == null)
{
item = getItemCallback(id);
CacheObject.Set(itemKey, item);
}
}
}
//
//
result.Add((TData)item);
}
}
//
//
return (List<TData>)result;
}
public static void Remove(string key)
{
CacheObject.Delete(key);
}
}
it is used in classes-repositories:
public class NewsRepository : BaseRepository, IRepository
{
public List<News> FindAll()
{
return CacheManager.Get<News>(key,
() => clientEntities.News.OrderByDescending(n => n.DateCreated).Select(n => n.NewsId).ToList(),
(id) => clientEntities.News.Single(n => n.NewsId == id));
}
}
public class PagesRepository : BaseRepository
{
public List<Page> FindAll()
{
return CacheManager.Get<Page>(key,
() => clientEntities.Pages.OrderBy(p => p.PageId).Select(p => p.PageId).ToList(),
(id) => clientEntities.Pages.Single(p => p.PageId == id));
}
}
my question is: for example NewsRepository didn't find news in cache and got the lock and began to load data but at this moment PagesRepository didn't find pages in cache. will PagesRepository's CacheManager be locked by NewsRepository or (I think so) NewsRepository's CacheManager is another static class and its internal locks do not touch PagesRepository's CacheManager?
A static field of a non-generic type (that is itself not nested in a generic type etc) exists only once, so all the locks will conflict.
If (comments) your aim is to make the lock per-type (from the generic method), then perhaps the best way to do that is:
public static class CacheManager {
static class TypeLock<T> {
public static readonly object SyncLock = new object();
}
...
void SomeGenericMethod<TData>(args) {
...
lock(TypeLock<TData>.SyncLock) {
...
}
...
}
}
Here, SyncLock exists once (and only once) per T, so per TData. This allows you to keep your existing API (where CacheManager is non-generic).
Both will use the same reference to lockObject, and therefore the same lock.