Skip to content

Instantly share code, notes, and snippets.

@cristipufu
Last active March 28, 2020 13:22
Show Gist options
  • Save cristipufu/273965fdfb203e16801e88251a72932a to your computer and use it in GitHub Desktop.
Save cristipufu/273965fdfb203e16801e88251a72932a to your computer and use it in GitHub Desktop.
// Curiously Recurring Pattern
// http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx
public class VersionedExecutorBase<T, TFunc>
where T : VersionedExecutorBase<T, TFunc>
{
private readonly Func<Version> _versionProvider;
private readonly Dictionary<Version, TFunc> _functions;
private TFunc _default;
public VersionedExecutorBase(Func<Version> versionProvider)
{
_versionProvider = versionProvider;
_functions = new Dictionary<Version, TFunc>();
}
public virtual T ForPreviousVersions(TFunc func)
{
_default = func;
return (T)this;
}
public virtual T ForVersion(Version version, TFunc func)
{
_functions.Add(version, func);
return (T)this;
}
public virtual TFunc GetFunction()
{
var currentVersion = _versionProvider();
if (currentVersion == null)
{
return _default;
}
var key = _functions.Keys
.Where(x => x <= currentVersion)
.OrderByDescending(x => x)
.FirstOrDefault();
return key != null ? _functions[key] : _default;
}
}
public class VersionedExecutor<T> : VersionedExecutorBase<VersionedExecutor<T>, Func<T, Task>>
{
public VersionedExecutor(Func<Version> versionProvider)
: base(versionProvider)
{
}
public virtual Task ExecuteAsync(T payload)
{
return GetFunction()(payload);
}
}
public class VersionedExecutor<TIn, TOut> : VersionedExecutorBase<VersionedExecutor<TIn, TOut>, Func<TIn, Task<TOut>>>
{
public VersionedExecutor(Func<Version> versionProvider)
: base(versionProvider)
{
}
public virtual Task<TOut> ExecuteAsync(TIn payload)
{
return GetFunction()(payload);
}
}
private VersionedExecutor<TIn, TOut> Versioner =>
new VersionedExecutor<TIn, TOut>(() => Info.Version)
.Default((TIn)payload =>
{
// Do something
return (TOut)object;
})
.For(ApplicationVersions.Firefly2, (TIn)payload =>
{
// Do something
return (TOut)object;
})
.For(ApplicationVersions.Firefly3, (TIn)payload =>
// Do something
return (TOut)object;
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment