I have a question regarding closures and heap allocation. Consider the following code:
//ORIGINAL CODE, VERSION 1
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(String x){
if(x == "abort") return null;
return _coll.GetOrAdd(x, (k)=> TestCallback());
}
public static object TestCallback() => null;
}
Within Test a static callback function is used. And, according to https://sharplab.io, this gets lowered to (abbr.):
//LOWERED CODE, VERSION 1
public class Program
{
private sealed class <>c
{
public static readonly <>c <>9 = new <>c(); // <== HELPER1 CREATION
public static Func<object, object> <>9__1_0;
internal object <Test>b__1_0(object k)
{
return TestCallback();
}
}
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(string x)
{
if (x == "abort")
{
return null;
}
return _coll.GetOrAdd(x, <>c.<>9__1_0 ?? (<>c.<>9__1_0 = new Func<object, object>(<>c.<>9.<Test>b__1_0))); // <== HELPER2 CREATION
}
public static object TestCallback() //==> STATIC METHOD
{
return null;
}
}
So, the compiler creates a few helper objects, but does this only once (the helpers are static).
Now, if I remove static from TestCallback...:
//ORIGINAL CODE, VERSION 1
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(String x){
if(x == "abort") return null;
return _coll.GetOrAdd(x, (k)=> TestCallback());
}
public object TestCallback() => null; //==> INSTANCE METHOD
}
...the lowered code changes to:
//LOWERED CODE, VERSION 2
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(string x)
{
if (x == "abort")
{
return null;
}
return _coll.GetOrAdd(x, new Func<object, object>(<Test>b__1_0)); // <== HELPER1 CREATION
}
public object TestCallback()
{
return null;
}
private object <Test>b__1_0(object k)
{
return TestCallback();
}
}
It now appears that a new Func is created on every call, if x == "abort" is not true (i.e. _coll.GetOrAdd is actually called).
Finally, if I change Test to include a callback parameter...:
//ORIGINAL CODE, VERSION 3
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(String x, Func<object> callback){
if(x == "abort") return null;
return _coll.GetOrAdd(x, (k)=> callback());
}
}
...the lowered code changes to:
//LOWERED CODE, VERSION 3
public class Program
{
private sealed class <>c__DisplayClass1_0
{
public Func<object> callback;
internal object <Test>b__0(object k)
{
return callback();
}
}
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(string x, Func<object> callback)
{
<>c__DisplayClass1_0 <>c__DisplayClass1_ = new <>c__DisplayClass1_0(); // <== HELPER1 CREATION
<>c__DisplayClass1_.callback = callback;
if (x == "abort")
{
return null;
}
return _coll.GetOrAdd(x, new Func<object, object>(<>c__DisplayClass1_.<Test>b__0)); // <== HELPER2 CREATION
}
}
Here, it appears as if, a new <>c__DisplayClass1_0 is created on every call, regardless of x == "abort".
To summarize:
Version1: create 2 helpers once.
Version2: create 1 helper whenever _cao..GetOrAdd is actually called.
Version3: create 2 helper on every call.
Is this correct? If the lowered code is correct (and is what the actual compiler uses), why is the creation of new <>c__DisplayClass1_0 not done immediately before the relevant call?
Then unneccessary allocations would be prevented. Ultimately I'm wondering, if this is an actual improvement:
public IMetadata GetOrDefineMetadata(object key, Func<IMetadata> createCallback)
{
if (_coll.TryGetValue(key, out var result)) return result; //THIS LINE WAS INSERTED AS AN IMPROVEMENT
return _coll.GetOrAdd(key, (k) => createCallback()); // ==> WILL THIS STILL CAUSE ALLOCATIONS ON EVERY CALL?
}
This looks like an opportunity for a compiler optimization.
I moved the call to _coll.GetOrAdd to a static method. In the lowered code this moves the allocation further down.
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(String x, Func<object> callback){
if(x == "abort") return null;
return GetOrAdd(x, _coll, callback);
}
private static object GetOrAdd(string x, ConcurrentDictionary<object, object> dict, Func<object> callback)
{
return dict.GetOrAdd(x, (_)=> callback());
}
}
Lowered version:
public class Program
{
[CompilerGenerated]
private sealed class <>c__DisplayClass2_0
{
public Func<object> callback;
internal object <GetOrAdd>b__0(object _)
{
return callback();
}
}
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(string x, Func<object> callback)
{
if (x == "abort")
{
return null;
}
return GetOrAdd(x, _coll, callback);
}
private static object GetOrAdd(string x, ConcurrentDictionary<object, object> dict, Func<object> callback)
{
<>c__DisplayClass2_0 <>c__DisplayClass2_ = new <>c__DisplayClass2_0();
<>c__DisplayClass2_.callback = callback;
return dict.GetOrAdd(x, new Func<object, object>(<>c__DisplayClass2_.<GetOrAdd>b__0));
}
}
Related
This question already has answers here:
Cannot use ref or out parameter in lambda expressions
(7 answers)
Closed 4 years ago.
How can I pass a ref to a lambda ? I've seend posts suggesting a delegate but I can't get it to work ..
I tried:
public class State<T>
{
public State() { }
public State(T t) { this.t = t; }
readonly object theLock = new object();
T t;
public void Lock(Action<ref T> action) { lock (theLock) action(ref t); }
}
however this does not compile, I get 'unexpected token ref'
I then tried:
public class State<T>
{
public State() { }
public State(T t) { this.t = t; }
readonly object theLock = new object();
T t;
public delegate void ActionRef<X>(ref X t);
public void Lock(ActionRef<T> action) { lock (theLock) action(ref t); }
}
Which compiles but I'm not able to use it
If I try:
var v = new State<int>(5);
v.Lock(t => t + 1);
I get Parameter 1 must be declared with the 'ref' keyword
If I try:
var v = new State<int>(5);
v.Lock(ref t => t + 1);
I get A ref or out value must be an assignable variable
How can I get this to work ? that is pass an Action to Lock which locks the lock and then calls the lambda with a ref ?
(tested in VS19 community preview .NET Core console app)
(this is different than Cannot use ref or out parameter in lambda expressions as there it's about a lambda using a ref in it's closure)
(credit goes to PetSerAI ..)
I was very close, State<T> is the same:
public class State<T>
{
public State() { }
public State(T t) { this.t = t; }
readonly object theLock = new object();
T t;
public delegate void ActionRef(ref T t);
public void Lock(ActionRef action) { lock (theLock) action(ref t); }
}
but using it is like this:
var s = new State<int>(5);
s.Lock((ref int v) => v=v+3);
For completion here is ReadOnlyState<T>:
public class ReadOnlyState<T>
{
public ReadOnlyState(T t) { this.t = t; }
readonly object theLock = new object();
readonly T t;
public delegate void ActionRef(in T t);
public void Lock(ActionRef action) { lock (theLock) action(in t); }
}
var ros = new ReadOnlyState<int>(5);
ros.Lock((in int v) => {
v.f();
v=2; // does not compile
});
Given this code:-
public class ExpressionEvaluatorAce: ExpressionEvaluator
{
readonly IContext target;
public ExpressionEvaluatorAce(IContext target, string criteria, Func<string, object> missingPropertyCallback = null):
base(missingPropertyCallback != null
? new EvaluatorContextDescriptorDefaultAce(TypeDescriptor.GetProperties(target), missingPropertyCallback)
: new EvaluatorContextDescriptorDefault(TypeDescriptor.GetProperties(target)),
CriteriaOperator.Parse(criteria))
{
this.target = target;
}
// Since we are passing in the target context anyway, might as well store it and just use it
public object Evaluate()
{
return Evaluate(target);
}
class EvaluatorContextDescriptorDefaultAce: EvaluatorContextDescriptorDefault
{
readonly PropertyDescriptorCollection properties;
readonly Func<string, object> missingPropertyCallback;
public EvaluatorContextDescriptorDefaultAce(PropertyDescriptorCollection properties, Func<string, object> missingPropertyCallback): base(properties)
{
this.properties = properties; // Copy since base.Properties is private!
this.missingPropertyCallback = missingPropertyCallback;
}
public override object GetPropertyValue(object source, EvaluatorProperty propertyPath)
{
if (properties.Find(propertyPath.PropertyPath, true) == null)
{
return missingPropertyCallback(propertyPath.PropertyPath);
}
return base.GetPropertyValue(source, propertyPath);
}
}
}
and it being called like this:-
result.Result = new ExpressionEvaluatorAce(context, reportSection.Condition,
missingProperty =>
{
if (missingProperty == "IgnoreSpec") return "XXX";
return null;
}
).Evaluate();
will this cause a memory leak if this code is in a long-lived class?
I have something like this. How can i return value form anonymous method?
returnRate = d;. For example let i have some class which get's messages from server. I want to process those messages in classes Cars and Bicycles is that clearly now?
namespace ConsoleApplication9
{
class Program
{
static void Main(string[] args)
{
Cars c = new Cars();
Bicycles b = new Bicycles();
}
}
public class Cars
{
public Cars()
{
GetData G1 = new GetData();
Dictionary<string, string> D1 = new Dictionary<string, string>();
G1.ProcessCars(ref D1);
}
}
public class Bicycles
{
public Bicycles()
{
GetData G2 = new GetData();
Dictionary<string, string> D2 = new Dictionary<string, string>();
G2.ProcessBicycles(ref D2);
}
}
public class Singleton
{
private static Singleton instance;
public Dictionary<string, Action<MessageEventArgs>> Handle;
private Singleton()
{
Handle = new Dictionary<string, Action<MessageEventArgs>>();
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
public class GetData
{
private Client socket;
public GetData()
{
socket = new Client("http://echo.jsontest.com/bicycles/10");
socket.Message += Message;
}
public void ProcessBicycles(ref Dictionary<string, string> returnRate)
{
Singleton.Instance.Handle.Add("bicycles", (m) =>
{
Dictionary<string, string> d = m.Message.Json.GetFirstArgAs<Dictionary<string, string>>() as Dictionary<string, string>;
//returnRate = d;
});
}
public void ProcessCars(ref Dictionary<string, string> returnRate)
{
Singleton.Instance.Handle.Add("cars", (m) =>
{
Dictionary<string, string> d = m.Message.Json.GetFirstArgAs<Dictionary<string, string>>() as Dictionary<string, string>;
//returnRate = d;
});
}
private void Message(object sender, MessageEventArgs e)
{
if (Singleton.Instance.Handle.ContainsKey(e.Message.Event))
{
Singleton.Instance.Handle[e.Message.Event](e);
}
}
}
}
You'll have to pass in the Action yourself, rather than creating it with a ref parameter. So your Add method simply becomes:
public void Add(Action<string> action) {
Handle.Add("1", action);
}
You can call it like this:
Add(m => ReturnRate = m);
This is a kind of Callback function, which can be used for a kind of asynchronous programming. However, it might be worth your time to read about async and await. If you could give us more information about what your scenario exactly is, we might be able to give you more hints.
If you have to use a ref parameter (for some strange reason), I think you're out of luck...
You should use Func<string,string> instead Action
Action<string> means void function(string s)
Func<string,string> means string function(string s)
However it depends on usage you want to achieve.
This is because the used variables that are used in the the anonymous method body but are outside of it, will be public fields in the generated class made by the compiler. But you can introduce a local variable to make it compilable:
public void Add(ref string rate)
{
string r = rate;
Handle.Add("1", (m) =>
{
Console.WriteLine(m);
r = m;
});
rate = r;
}
And the compiler will generate this in the background:
public void Add(ref string rate)
{
<>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.r = rate;
this.Handle.Add("1", new Action<string>(CS$<>8__locals2.<Add>b__0));
rate = CS$<>8__locals2.r;
}
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
public string r;
public void <Add>b__0(string m)
{
Console.WriteLine(m);
this.r = m;
}
}
Note: Though this can be compiled, it will not work as you expect, because calling the outer Add will not execute the delegate added by Handle.Add. To return the m from the inner delegate you must use a Func instead.
You should use Func<string,string> (delegate Func<in T,out TResult>) which is equivalent to some function that takes in string and returns string
for eg:-
private string MyFunction(string inputstring){}
Whereas Action<string> (delegate Action<in T>) corresponds to a function which only takes input and returns nothing
private void MyFunction(string inputstring){}
You can modify your code to something like
private Dictionary<string, Func<string,string>> Handle;
private string ReturnRate;
public data()
{
Handle = new Dictionary<string, Func<string,string>>();
Add(ref ReturnRate);
Handle["1"]("MyValue");
Console.WriteLine(ReturnRate);
}
public void Add(ref string rate)
{
string somevalue=rate;
Handle.Add("1", (m) =>
{
Console.WriteLine(m);
somevalue= m;
return m;
});
}
I've just created some kind of generic repository, it seems to be working, my only problem is, is there any solution to avoid to use public constructor in classes what has to be instantiated to the repository?
My code is here:
public sealed class repository
{
private static readonly object _lock = new object();
private static readonly object _syncroot = new object();
private static volatile repository _instance;
private static readonly Dictionary<int, object> _dict
= new Dictionary<int, object>();
private repository()
{
}
public static repository instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null) _instance = new repository();
}
}
return _instance;
}
}
public void allocate<Tc>(int id, object constructor_param) where Tc : Irepository<Tc>, new()
{
lock (_syncroot)
{
if (!_dict.ContainsKey(id))
{
var n = new Tc();
_dict.Add(id, n.New(constructor_param));
}
}
}
public T get<T>(int id)
{
lock (_syncroot)
{
return (T) _dict[id];
}
}
}
public interface Irepository<out T>
{
T New(object constructor_param);
}
public class RpSupportedClass : Irepository<RpSupportedClass>
{
public object _constructor_param;
private RpSupportedClass(object constructor_param)
{
_constructor_param = constructor_param;
}
public RpSupportedClass()
{
}
public RpSupportedClass New(object constructor_param)
{
return new RpSupportedClass(constructor_param);
}
}
So the problem is that I have to create a default public constructor:
public RpSupportedClass()
{
}
...because of type parameter. I need type parameter by this way because I would like to use parameter in class instantiate sometimes.
Is there any way out?
Thank you!
I have a C# WebAPI that has a query which collates a lot of data. Subsequently, I am using HttpRuntime cache to cache the result object for 10 mins. The problem is, when the cache expires, that person gets a 12 second load. This application utilises 3 delivery servers and we don't have the option of distributed cache.
Using .NET, we can use the cache expired event, but how best to use that without impacting the calling request?
One thought was to have a never expires cache, so that if the main cache is expired, fallback to that, then have a windows service or similar which polls every 5 mins to refresh both caches.
Ideas?
Perhaps caching the results separately to the page cache will help.
Based on http://johnnycoder.com/blog/2008/12/10/c-cache-helper-class/
Since it is static, you could use WCF to refresh at your own pace.
I modified to be static and not http
public static class CacheHelper
{
public static void WriteOutCacheHelper()
{
foreach (KeyValuePair<string, object> cache in Cache)
{
Console.WriteLine(cache.Key);
}
}
public static void WriteOutCacheHelper(string key)
{
Console.WriteLine(Get<object>(key).ToString());
}
public static bool Enabled { get; set; }
private static Dictionary<string, object> _cache;
public static Dictionary<string, object> Cache
{
get
{
if (_cache == null) _cache = new Dictionary<string, object>();
return _cache;
}
}
public static object lockObject = new object();
public static void Add<T>(T o, string key)
{
if (!Enabled) return;
lock (lockObject)
{
if (Exists(key))
Cache[key] = o;
else
Cache.Add(key, o);
}
}
public static void Clear(string key)
{
if (!Enabled) return;
Cache.Remove(key);
}
public static bool Exists(string key)
{
if (!Enabled) return false;
return Cache.ContainsKey(key);
}
public static T Get<T>(string key)
{
if (!Enabled) return default(T);
T value;
try
{
value = (!Exists(key) ? default(T) : (T) Cache[key]);
}
catch
{
value = default(T);
}
return value;
}
public static void ClearAll(bool force = false)
{
if (!force && !Enabled) return;
Cache.Clear();
}
public static List<T> GetStartingWith<T>(string cacheKey) where T : class
{
if (!Enabled) new List<T>();
return Cache.ToList().FindAll(f => f.Key.StartsWith(cacheKey, StringComparison.CurrentCultureIgnoreCase))
.Select(s => s.Value as T).ToList();
}
}