【问题标题】:How do I construct an Action<T> from lambda expression?如何从 lambda 表达式构造 Action<T>?
【发布时间】:2018-10-26 22:41:47
【问题描述】:

我有这个代码:

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 应分配给 Action&lt;T&gt;,但编译器报错:错误 CS1628:无法在匿名方法、lambda 表达式或查询表达式中使用 ref 或 out 参数“thisArg”

否则我该如何使用Action&lt;T&gt;

编辑:

这是类型声明:

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;

}

【问题讨论】:

  • 为什么是ref this T thisArg 而不是this T thisArg?如果这甚至可行,那么扩展方法是非常不寻常的。
  • @John Wu,它有效。就是这样,因为我需要构造一个 Action ,它会在以后更改 ref thisArg 但方法是扩展方法,所以我需要 ref this。
  • 包含thisArg的原始变量存储在哪里?除了传递变量 byref,也许您可​​以按值传递包含它的对象。
  • 这是什么版本的 C#?我不希望“ref this”能够编译 - 当然对我来说,我得到“参数修饰符 'ref' 不能与 'this' 一起使用”。这是有道理的——毕竟,一个普通的类方法不能改变this所指的东西,那么为什么扩展应该能够呢?
  • @Dylan Nicholson 这是 C# 7.2

标签: c#


【解决方案1】:

您可以删除 ref 关键字并将其替换为不同形式的间接寻址,例如一个容器类。在此示例中,我创建了一个名为 Ref 的容器类,该类仅用于保存另一个值。

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

我仍然不能再通过引用传递任何东西,但是如果我传递一个Ref 对象,该方法可以更新它的属性。

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

输出:

Value before call is: Before
Value after call is: After

查看DotNetFiddle 上的工作示例。

编辑:要将解决方案放入您的代码中,您的代码可能如下所示:

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

【讨论】:

  • 我不能使用包装类,我需要一个通用的扩展方法。
  • TweenExecuter 适用于任何类型。我可以将它用作 float.TweenExecuter()、Vector3.TweenExecuter()。随着您的更改,扩展将仅适用于 Ref、Ref
  • 仔细检查自己。类型约束来自 your 示例。显然,您可以将其修改为您想要的任何内容。我的解决方案适用于任何类型。
  • 看看它是如何不起作用的:dotnetfiddle.net/B3H6PN 预期用途是 AnyTypeVariable.ExtensionMethod() 而不是 Ref.ExtensionMethod()
  • 你没有抓住重点。你必须包装int。或任何其他类型。有什么理由你不能?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多