Lambda/Action with a local ref [duplicate] - c#

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

Related

Why aren't closure helper instances (DisplayClass) only created when actually needed?

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

How do I construct an Action<T> from lambda expression?

I have this code:
public static Tween.TweenExecuter To<T>(ref this T thisArg, T to, float time, EasingType easing = EasingType.Linear,
TweenType type = TweenType.Simple, Func<bool> trigger = null, Action callback = null) where T : struct
{
Tween.TweenElement<T> tween = new Tween.TweenElement<T>()
{
from = thisArg,
Setter = x => thisArg = x,
to = to,
time = time,
easing = easing,
type = type,
Trigger = trigger,
Callback = callback
};
tween = t;
return new Tween.TweenExecuter(tween);
}
Setter should be assigned to an Action<T> but compiler complains: error CS1628: Cannot use ref or out parameter 'thisArg' inside an anonymous method, lambda expression, or query expression
How can I use an Action<T> otherwise?
Edit:
Here is the type declaration:
public abstract class BaseTween
{
public float time;
public float currentTime;
public EasingType easing;
public TweenType type;
public bool deleteAtEnd = false;
public Func<bool> Trigger;
public Action Callback;
}
public class TweenElement<T> :BaseTween
{
public Action<T> Setter;
public T from;
public T to;
}
You can eliminate the ref keyword and replace it with a different form of indirection, e.g. a container class. In this example I create a container class named Ref which is designed solely to hold another value.
class Ref<T>
{
public T Value { get; set; }
public Ref(T item)
{
Value = item;
}
public override string ToString()
{
return Value.ToString();
}
public static implicit operator T(Ref<T> source)
{
return source.Value;
}
}
I can still no longer pass anything by reference, but if I pass a Ref object, the method can update its properties.
public class Program
{
static Ref<Foo> _container = new Ref<Foo>(null);
static void MyMethod(Ref<Foo> thisArg)
{
Action action = () => thisArg.Value = new Foo("After");
action();
}
public static void Main()
{
_container.Value = new Foo("Before");
Console.WriteLine("Value before call is: {0}", _container);
MyMethod(_container);
Console.WriteLine("Value after call is: {0}", _container);
}
}
Output:
Value before call is: Before
Value after call is: After
See a working example on DotNetFiddle.
Edit: To put the solution into your code, here is what yours might look like:
public static Tween.TweenExecuter To<T>(this Ref<T> thisArg, T to, float time, EasingType easing = EasingType.Linear, TweenType type = TweenType.Simple, Func<bool> trigger = null, Action callback = null) where T : struct
{
Tween.TweenElement<T> tween = new Tween.TweenElement<T>()
{
from = thisArg,
Setter = x => thisArg.Value = x,
to = to,
time = time,
easing = easing,
type = type,
Trigger = trigger,
Callback = callback
};
return new Tween.TweenExecuter(tween);
}

c# - Call the good overloaded method from a function with an unkown parameter type

I am trying to call the good overloaded method from a function with an unkown parameter type. But I always got a conversion error.
How Could I do this ?
Ps I am Trying to not use a if to check the Type.
I Have Try To Change my function to be generic but I got a conversion error.
"Impossible to convert ref T in ref MYPROGRAM.MYCLASS.Struct1"
My Program:
public struct Struct1
{...}
public struct Struct2
{...}
public void EditStruct(ref Struct1 StrucToEdit)
{...}
public void EditStruct(ref Struct2 StrucToEdit)
{...}
public void MyFunction<T>(ref T UnknownStruct)
{
EditStruct(ref UnknownStruct)
}
Thx a lot.
Here is a simple solution using reflection. In this case the reflection results can be very good cached, the performance hit should not be that bad.
class Program
{
static void Main(string[] args)
{
var x = new Struct1() { A = 0, B = -10 };
var y = new Struct2() { C = 0, D = -10 };
MyFunction(ref x);
MyFunction(ref y);
}
public static void EditStruct(ref Struct1 structToEdit)
{
structToEdit = new Struct1() { A = 10, B = 20 };
}
public static void EditStruct(ref Struct2 structToEdit)
{
structToEdit = new Struct2() { C = 30, D = 40 };
}
private delegate void EditDelegate<T>(ref T obj);
public static void MyFunction<T>(ref T unknownStruct)
{
Delegate d;
if (!_dict.TryGetValue(typeof(T), out d))
{
d = typeof(Program).Assembly.GetTypes()
.SelectMany(x => x.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly))
.Single(x => x.Name == "EditStruct" && x.GetParameters().SingleOrDefault(y => y.ParameterType.Equals(typeof(T).MakeByRefType())) != null)
.CreateDelegate(typeof(EditDelegate<T>));
_dict.Add(typeof(T), d);
}
(d as EditDelegate<T>)(ref unknownStruct);
}
private static readonly Dictionary<Type, Delegate> _dict = new Dictionary<Type, Delegate>(new TypeComparer());
class TypeComparer : IEqualityComparer<Type>
{
public bool Equals(Type x, Type y) => x.Equals(y);
public int GetHashCode(Type obj) => obj.GetHashCode();
}
}
public struct Struct1
{
public int A;
public int B;
}
public struct Struct2
{
public int C;
public int D;
}
Very small OO example that might help - in this example the code to perform the editing is encapsulated away using the IStructEditor interface:
public static class StructEditor
{
public static void Edit<TStruct, TEditor>(ref TStruct s)
where TEditor : IStructEditor<TStruct>, new()
{
new TEditor()
.EditStuct(ref s);
}
}
public interface IStructEditor<T>
{
void EditStuct(ref T s);
}
struct CostStruct
{
public int Cost;
}
class SetCost
: IStructEditor<CostStruct>
{
public void EditStuct(ref CostStruct s)
{
s.Cost = 123;
}
}
So you can use this as follows:
CostStruct s = new CostStruct();
StructEditor.Edit<CostStruct, SetCost>(ref s);
Meaning you can quickly define new behaviors by implementing IStructEditor!
I dont' even understand what are you doing, but it seams unnecessary to do any casting on a generic method, the type is already known!
Just call EditStruct(ref UnknownStructCasted), deleting first line.
Parameter is of type T, not dynamic. It will be only if you call your method
EditStruct(new dynamic{
//some data
});
Aren't you?
Working sample:
internal class Program
{
public enum WhatToDo
{
Something,
SomethingElse
}
public static void MyMethod(WhatToDo what)
{
switch (what)
{
case WhatToDo.Something:
Struct1 param1 = new Struct1();
MygenericMethod(param1);
break;
case WhatToDo.SomethingElse:
Struct2 param2 = new Struct2();
MygenericMethod(param2);
break;
}
}
public static void MygenericMethod<T>(T someParam) where T : struct
{
}
public struct Struct1
{
}
public struct Struct2
{
}
}
If you can find a common interface for your structs, consider something like:
class Program
{
static void Main(string[] args)
{
IStruct s1 = new Struct1();
IStruct s2 = new Struct2();
EditStruct(ref s1);
EditStruct(ref s2);
}
static void EditStruct(ref IStruct target)
{
target.Name = Guid.NewGuid().ToString();
}
}
public interface IStruct
{
string Name { get; set; }
}
public struct Struct1 : IStruct
{
public string Name { get; set; }
}
public struct Struct2: IStruct
{
public string Name { get; set; }
}

c# method as parameter where method contains ref paramater [duplicate]

This question already has answers here:
Delegate for an Action< ref T1, T2>
(2 answers)
Closed 7 years ago.
I have got the following method
public static void Method1(ref List<int> list)
{//code to update list}
Is it possible to create a method that takes this method as a parameter similar to (but instead of Action< List> it uses Action< ref List>)
public static void Method2(Action<List<int>> otherMethod)
{var newList = new List<int>(); otherMethod(newList)}
My main problem is that my method uses reference while Action> does not take references. Is this possible?
Yes, but you can't use Action<>/Func<> for it, you have to build the delegate "manually":
// Your method
public static void Method1(ref List<int> list)
{
}
// The delegate
public delegate void Method1Delegate(ref List<int> list);
// A method that accepts the delegate and uses it
public static void Method2(Method1Delegate del)
{
List<int> list = null;
del(ref list);
}
class App
{
private readonly Dictionary<Type, object> delegateMap;
void Add<T>(Action<SomeClass<T>> foo)
{
object tmp;
if (!delegateMap.TryGetValue(typeof(T), out tmp))
{
tmp = new List<Action<SomeClass<T>>>();
delegateMap[typeof(t)] = tmp;
}
List<Action<SomeClass<T>> list = (List<Action<SomeClass<T>>) tmp;
list.Add(foo);
}
void InvokeActions<T>(SomeClass<T> item)
{
object tmp;
if (delegateMap.TryGetValue(typeof(T), out tmp))
{
List<Action<SomeClass<T>> list = (List<Action<SomeClass<T>>) tmp;
foreach (var action in list)
{
action(item);
}
}
}
}
Use Delegates.

How cast Generic T to Action<...> to get the Method params

Hi i'm try to cast a generic to an Action with a unknown number and type of Parameters
at the moment it looks like:
public class subscriber
{
public subscriber()
{
new Subscription<Action>(a);
new Subscription<Action<string>>(b);
new Subscription<Action<int,string>>(c);
}
private void a() { }
private void b(string gg){}
private void c(int i, string g) { }
}
public class Subscription<T>
{
public T MyAction {get {retun _action;}}
public Type MyActionType {get;private set;}
public Subscription( T action )
{
MyAction = action;
MyActionType = action.GetType();
var gg = action.GetType().GetGenericArguments();// Contains the Sub generics
}
}
at the moment we know it will be an Action and we also know the Sub Types but how to put this all together
to execute my private void c(int i, string g) method
Final Goal
is to execute the Action from a Third-Class (which will contains a List<Subscription> ) when a Fourth-Class hand over some params
public abstract class SubscriptionBase
{
public abstract void ExecuteAction(params object[] parameters);
}
public class Subscription<T> : SubscriptionBase
{
private T _action;
public Subscription(T a)
{
_action = a;
}
public override void ExecuteAction(params object[] parameters)
{
(_action as Delegate).DynamicInvoke(parameters);
}
}
and you can use it like;
Action<int> func1 = (q) => q += 1;
Action<int, int> func2 = (q, w) => q += w;
Subscription<Action<int>> s1 = new Subscription<Action<int>>(func1);
Subscription<Action<int, int>> s2 = new Subscription<Action<int, int>>(func2);
List<SubscriptionBase> subscriptionBase = new List<SubscriptionBase>();
subscriptionBase.Add(s1);
subscriptionBase.Add(s2);
subscriptionBase[1].ExecuteAction(1, 2);
You can't do it that way. You can't put a Subscription<Action<int>> into the same list as Subscription<Action<string, Foo>>.
I suggest, you create an interface like the following and store those in your third class:
interface IActionExecutor
{
bool CanExecuteForParameters(params object[] parameters);
void Execute(params object[] parameters);
}
// Implementation for one parameter
// You need to create one class per additional parameter.
// This is similar to the Action delegates in the framework.
// You can probably extract a base class here that implements
// some of the repetitive pars
public class ActionExecutor<in T> : IActionExecutor
{
private Action<T> _action;
public ActionExecutor(Action<T> action)
{
if(action == null) throw new ArgumentNullException("action");
_action = action;
}
public bool CanExecuteForParameters(params object[] parameters)
{
if(parameters == null) throw new ArgumentNullException("action");
if(parameters.Length != 1) return false;
return parameters[0] is T;
}
public void Execute(params object[] parameters)
{
if(parameters == null) throw new ArgumentNullException("action");
if(parameters.Length != 1)
throw new ArgumentOutOfRangeException("action");
_action((T)parameters[0]);
}
}
In your third class you would have the list of IActionExecutors:
List<IActionExecutor> _subscriptions;
And you would use it like this:
public void Execute(params object[] parameters)
{
var matchingSubscriptions =
_subscriptions.Where(x => x.CanExecuteForParameters(parameters);
foreach(var subscription in matchingSubscriptions)
subscription.Execute(parameters);
}
To simplify the creation of those ActionExecutor instances, you can provide a factory class:
public static class ActionExecutor
{
public IActionExecutor Create(Action action)
{
return new ActionExecutor(action);
}
public IActionExecutor Create<T>(Action<T> action)
{
return new ActionExecutor<T>(action);
}
public IActionExecutor Create<T1, T2>(Action<T1, T2> action)
{
return new ActionExecutor<T1, T2>(action);
}
// ... and so on
}
Usage would now be like this:
_subscriptions.Add(ActionExecutor.Create(a));
_subscriptions.Add(ActionExecutor.Create(b));
_subscriptions.Add(ActionExecutor.Create(c));

Categories

Resources