Vlad Radu
Vlad Radu

Reputation: 367

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;

}

Upvotes: 0

Views: 131

Answers (1)

John Wu
John Wu

Reputation: 52280

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

Upvotes: 1

Related Questions