c# lock in generic function - c#

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.

Related

Short circuit yield return & cleanup/dispose

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;
}
}
}

Refactoring static class into multiple implementations

I am using a cache item as described by https://blog.falafel.com/working-system-runtime-caching-memorycache/
However I need to develop a number of implementations of this class which use different tables within the ConsentDataContext item.
This class is a static, so I either need to change it to a singleton and then inherit from an abstract with GetItem and AddOrGetExisting methods defined. Or create two separate classes and use reflection to return the correct instance.
What would be the best way of solving this problem?
Implementation 1
public static class Consent1Cache
{
private static MemoryCache _cache = new MemoryCache("ConsentType1Cache");
public static object GetItem(string key)
{
return AddOrGetExisting(key, () => InitItem(key));
}
private static T AddOrGetExisting<T>(string key, Func<T> valueFactory)
{
var newValue = new Lazy<T>(valueFactory);
var oldValue = _cache.AddOrGetExisting(key, newValue, new CacheItemPolicy()) as Lazy<T>;
try
{
return (oldValue ?? newValue).Value;
}
catch
{
// Handle cached lazy exception by evicting from cache.
_cache.Remove(key);
throw;
}
}
public static string InitItem(string consentNumber)
{
using (DLL.ConsentDataContext db = new DLL.ConsentDataContext())
{
return db.vw_ConsentType1.Where(x => x.ConsentNumber == consentNumber).Select(c => c.ConsentNumber + " - " + c.Proposal).FirstOrDefault();
};
}
}
Implementation 2
public static class Consent2Cache
{
private static MemoryCache _cache = new MemoryCache("ConsentType2Cache");
public static object GetItem(string key)
{
return AddOrGetExisting(key, () => InitItem(key));
}
private static T AddOrGetExisting<T>(string key, Func<T> valueFactory)
{
var newValue = new Lazy<T>(valueFactory);
var oldValue = _cache.AddOrGetExisting(key, newValue, new CacheItemPolicy()) as Lazy<T>;
try
{
return (oldValue ?? newValue).Value;
}
catch
{
// Handle cached lazy exception by evicting from cache.
_cache.Remove(key);
throw;
}
}
public static string InitItem(string consentNumber)
{
using (DLL.ConsentDataContext db = new DLL.ConsentDataContext())
{
return db.vw_ConsentType2.Where(x => x.ConsentNumber == consentNumber).Select(c => c.ConsentNumber + " - " + c.Proposal).FirstOrDefault();
};
}
}

Build dynamic predicate based on generic type

How do I make this expression dynamic based on the generic type passed in the parameter?
In the simplified form:
public static class CompareService
{
public static List<T> Run<T>(List<T> database_list, string directory_path)
{
var csv_list = CompareService.MergeRecordsFromFiles<T>(directory);
return CompareService.RunComparison<T>(database_list, csv_list);
}
public static T CompareData<T>(List<T> database_list, List<T> csv_list)
{
var diff = new List<T>();
foreach (var db_item in database_list)
{
// ...
// if T is of type Deathstar compare reference_number property
// if T is of type Stormtrooper compare id property
// if T is of type Sith compare id and anger_level property
var csv_item = csv_list.FirstOrDefault(x => x.reference_number == db_item.reference_number);
// Comparison code
ComparisonResult result = compareLogic.Compare(db_item, csv_item);
// ...
}
return diff;
}
}
It is called from another generic service:
public static void Whatever<T>(List<T> list)
{
// ...
var directory_path = "C:\";
var delta = CompareService.CompareData<T>(list, directory_path);
// ...
}
The most naive implementation would be to check if your itemToFind can be cast to DeathStar, StormTrooper or Sith and if so call the instances property.
var deathStar = itemToFind as DeathStar;
if(deathStar != null)
return database_list.Where(x => ((DeathStar)x).reference_number == deathStar.reference_number).FirstOrDefault();
else
{
var sith = itemToFind as Sith;
if(sith != null)
return database_list.Where(x => ((Sith)x).anger_level == sith.anger_level).FirstOrDefault();
else
return database_list.Where(x => ((StormTrooper)x).id== ((StormTrooper)item).id).FirstOrDefault();
}
This is quite cumbersome, including many casts. In particular it completely bypasses the actual benefits of generics using any arbitrary type (that fullfills the constraints if existing). In your case you´d have a generic method that will only wortk for three decent types.
A better approach is to let all your classes implement a common interface that defines a property, for instance:
interface IObject {
int Level { get; }
}
Now all classes define that level-property:
clas DeathStar : IObject
{
public int Level { get { return this.reference_number; } }
}
clas Sith : IObject
{
public int Level { get { return this.anger_level; } }
}
clas StormTrooper: IObject
{
public int Level { get { return this.id; } }
}
Than you can use a constraint on your type T to implement that interface:
public static T CompareData<T>(List<T> list, T itemToFind) where T: IObject
Why not like this:
public static T CompareData<T>(List<T> list, Func<T, bool> predicate)
{
return database_list.FirstOrDefault(predicate);
}
And then use it like this:
var itemToFind = new ItemToFind();
var myObjectList = new List<MyObject>();
var item = CompareData<MyObject>(myObjectList, x=> x.MyObjectProperty == itemToFind.Id);
You could add a property selector:
public static class CompareService
{
public static T CompareData<T>(this List<T> list, T itemToFind, Func<T, int> propSelector)
{
int propToFind = propSelector(itemToFind); // cache
return database_list.FirstOrDefault(x => propSelector(x) == propToFind);
}
}
And call it like that:
listOfDeathstars.CompareData(deathStarToFind, ds => ds.reference_number);
listOfStormtroopers.CompareData(trooperToFind, t => t.id);
listOfSiths.CompareData(sithStarToFind, sith => new { sith.id, sith.anger_level});
Note: I added the this keyword in the signature to make it an extension (not sure if you intended that but forgot the keyword). And Where(predicate).FirstOrDefault() can be reduced to FirstOrDefault(predicate).

ReleaseObject of ITinyIoCObjectLifetimeProvider is not being called

I have implemented custom lifetime provider in order to have singleton DB context per job in hangfire. The problem in code below is that created instances are not being released.
My question is: Why ReleaseObject method is not called?
public class JobContextLifetimeProvider : TinyIoCContainer.ITinyIoCObjectLifetimeProvider
{
private static readonly ConcurrentDictionary<string, object> Locator = new ConcurrentDictionary<string, object>();
public object GetObject()
{
var key = JobContext.JobId;
return Locator.ContainsKey(key) ? Locator[key] : null;
}
public void SetObject(object value)
{
var key = JobContext.JobId;
Locator[key] = value;
if (value is IDataContext)
{
Debug.WriteLine("Created data context {0}", value.GetHashCode());
}
}
public void ReleaseObject()
{
var item = GetObject() as IDisposable;
if (item != null)
{
item.Dispose();
SetObject(null);
}
}
}

ConcurrentDictionary InvalidOperationException c#

this is the error:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List1.Enumerator.MoveNextRare()
at System.Collections.Generic.List1.Enumerator.MoveNext()
at System.Linq.Enumerable.WhereListIterator1.MoveNext()
at System.Linq.Enumerable.Count[TSource](IEnumerable1 source)
Blockquote
I use the static Dictionary for web api
this is my class that i use for my web api :
public class UsersSecureProvider
{
public static ConcurrentDictionary<short, List<UserSecure>> _Users = new ConcurrentDictionary<short, List<UserSecure>>();
public bool Add(short Group, UserSecure Message)
{
try
{
var GetList = GetByKey(Group);
if (GetList != null)
{
GetList.Add(Message);
return Update(Group, GetList, GetList);
}
else
{
GetList = new List<UserSecure>();
GetList.Add(Message);
return Add(Group, GetList);
}
}
catch { }
return false;
}
private bool Add(short key, List<UserSecure> SendUser)
{
return _Users.TryAdd(key, SendUser);
}
public bool Remove(short Key)
{
List<UserSecure> listremove;
return _Users.TryRemove(Key, out listremove);
}
public List<UserSecure> GetByKey(short Group)
{
var listView = new List<UserSecure>();
if (_Users != null)
{
var getList = _Users.TryGetValue(Group, out listView);
}
return listView;
}
public bool Update(short Group, List<UserSecure> oldlist, List<UserSecure> newlist)
{
return _Users.TryUpdate(Group, newlist, oldlist);
}
public void Clear()
{
_Users.Clear();
}
public ConcurrentDictionary<short, List<UserSecure>> GetAll()
{
return _Users;
}
public bool UpdateListByUser(short Group, List<UserSecure> newlist)
{
var OldList = GetByKey(Group);
return _Users.TryUpdate(Group, newlist, OldList);
}
}
And I call the class
var _providers = new UsersSecureProvider();
List<UserSecure> GetAll = _providers.GetByKey(1);
if (GetAll != null && GetAll.Any() && GetAll.Where(w => w.UserID == UserID && w.Key == UniqueSecure).Count() > 0)
{
result = true;
}
else
{
_providers.Add(1, new UserSecure { UserID = UserID, Key = UniqueSecure });
}
why do i receive this error exception?
thank you.
This:
List<UserSecure> GetAll = _providers.GetByKey(1);
Returns a reference to the underlying collection. That same reference to a list which is probably being modified via one of the other WebAPI actions you have. You cannot both enumerate and modify the List<T>.
Instead, create a new List<T> and enumerate it:
List<UserSecure> GetAll = _providers.GetByKey(1).ToList();
If your application is multi threading it is recomanded to use semaphore. For example
private static object _sync = new object();
public List<UserSecure> GetByKey(short Group)
{
lock(_sync)
{
var listView = new List<UserSecure>();
if (_Users != null)
{
var getList = _Users.TryGetValue(Group, out listView);
}
return listView;
}
}

Categories