【问题标题】:How to set property value at a later time以后如何设置属性值
【发布时间】:2014-09-04 20:34:15
【问题描述】:

我正在寻找一种机制,它允许我仅在满足某些条件时才推迟设置参数的支持字段。在遇到障碍之前,我一直在考虑这个设计,因为它需要在 lambda 表达式中使用 ref 参数。有没有办法在不需要将 ref 参数放入 lambda 的情况下做到这一点?

protected bool isRunning = false;
List<Action> argumentSetters = new List<Action>();
// the reason for the delegate and following subroutine
// is to define an action which takes a ref parameter
protected delegate void setArgByRef<T>(ref T arg, T value);
protected void setArgByRefSub<T>(ref T arg, T value)
{
    arg = value;
}
protected int _setPoint;
public int SetPoint
{
    get { return _setPoint; }
    set { setValue(ref _setPoint, value); }
}
public void Run()
{
    isRunning = true;
    // time consuming code here
    // don't want SetPoint to be allowed to change
    // while isRunning == true 
    isRunning = false;
    // set SetPoint and other properties after
    argumentSetters.ForEach((a) => a.Invoke());
}
protected void setValue<T>(ref T arg, T value)
{
    setArgByRef<T> a = new setArgByRef<T>(setArgByRefSub<T>);
    if (isRunning)
    // cannot use ref parameter inside a lambda
    { argumentSetters.Add(() => a.Invoke(ref arg, value)); }
    else
    { arg = value; }
}

【问题讨论】:

  • 你可以使用() =&gt; _setPoint = value action lambda吗?
  • 不在 setValue() 内部,因为它特定于 _setPoint,而我想使用 setValue 的原因是因为这是一个抽象类,所以我想将属性设置器内部的实现保持在最小限度。 SetPoint 只是一个示例,在派生类中定义的更多道具应该以相同的方式处理。

标签: c# lambda ref


【解决方案1】:

我能想到的最佳解决方案是Expression。想法是存储属性持有对象、属性信息和要设置的值,然后在准备好时进行设置。

从我写的另一个answer 中提取一点,你可以有一个函数从表达式中获取PropertyInfo

public static PropertyInfo GetPropertyInfo<TIn, TOut>(Expression<Func<TIn, TOut>> PropertyExpression)
{
    MemberExpression memberExpr;
    switch (PropertyExpression.Body.NodeType)
    {
        case ExpressionType.MemberAccess:
            memberExpr = (MemberExpression)PropertyExpression.Body;
            break;
        case ExpressionType.Convert:
            memberExpr = (MemberExpression)((UnaryExpression)PropertyExpression.Body).Operand;
            break;
        default:
            throw new NotSupportedException();
    }

    var property = (PropertyInfo)memberExpr.Member;
    return property;
}

然后你可以写一组要设置的东西:

private static readonly List<Tuple<object, PropertyInfo, object>> _ToSet = new List<Tuple<object, PropertyInfo, object>>();

然后根据需要添加到该列表中。

public static void AddPendingSet<TType, TProperty>(TType obj, Expression<Func<TType, TProperty>> expr, TProperty val)
{
    var prop = GetPropertyInfo(expr);

    _ToSet.Add(new Tuple<object, PropertyInfo, object>(obj, prop, val);
}

您甚至可以将其提取到两种方法中,并在需要时直接传递PropertyInfo。这可能会派上用场,具体取决于您的实施。

而且,当您需要全部设置时:

foreach (var v in _ToSet)
{
    v.Item2.SetValue(v.Item1, v.Item3);
}

当然,如果更合适的话,您也可以取出 obj 参数并改用 this。如果这成为现实世界的代码,我会很想不使用Tuple,因为它有点乱,但我在这里使用它来使这个例子最小化和完整。当然,无论哪种方式都应该有效。

问题在于它不适用于您正在使用的字段,但您可以设置一个属性并使用this,这应该可以工作。可能还有一种方法可以使表达式与字段一起使用,我只是从来不需要,所以我不确定。

为了更好地衡量,您可以像这样调用AddPendingState 方法。我编了TypeA作为例子。

AddPendingState<TypeA, int>(instance, c => c.PropertyName, 2);

【讨论】:

  • 我曾考虑过使用反射,但没有想到表达式。我会试试看。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-09
  • 2021-09-19
  • 2014-08-14
  • 1970-01-01
  • 2011-06-03
  • 2023-03-22
  • 1970-01-01
相关资源
最近更新 更多