0

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;

}
8
  • Why ref this T thisArg instead of this T thisArg? If that even works, it's very unusual for an extension method. Commented Oct 26, 2018 at 22:45
  • @ John Wu, it works. It's like that because I need to construct an Action<T> which will change ref thisArg at a later time but the method it's an extension method so I need ref this. Commented Oct 26, 2018 at 22:51
  • Where do you store the original variable that contains thisArg? Instead of passing the variable byref, perhaps you could pass the object that contains it by value. Commented Oct 27, 2018 at 0:13
  • What version of C# is this? I wouldn't expect "ref this" to compile - certainly for me I get "the parameter modifier 'ref' cannot be used with 'this'". Which makes sense - after all, a regular class methods can't change what this refers to, so why should an extension be able to? Commented Oct 27, 2018 at 1:31
  • @Dylan Nicholson it's C# 7.2 Commented Oct 27, 2018 at 7:47

1 Answer 1

1

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);
}
Sign up to request clarification or add additional context in comments.

6 Comments

I can't use a wrapper class, I need a generic extension method.
TweenExecuter will work for any kind of type. I can use it as float.TweenExecuter(), Vector3.TweenExecuter(). With your change, the extension will only work for Ref<float>, Ref<Vector3>.
Double check yourself. The type constraint is from your example. Obviously you can modify it to anything you want. My solution works for any type.
See how it doesn't work: dotnetfiddle.net/B3H6PN Intended use is AnyTypeVariable.ExtensionMethod() not Ref<AnyTypeVariable>.ExtensionMethod()
You're missing the point. You have to wrap the int. Or any other type. Some reason you can't?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.