2014-09-04 73 views
2

我正在寻找一种机制,只有在满足某些条件时才允许延迟参数的后台字段的设置。我一直认为这个设计直到我遇到困难,因为它需要在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; } 
} 
+0

你可以使用'()=> _setPoint = value'动作lambda吗? – 2014-09-04 20:36:49

+0

不在setValue()内,因为这是特定于_setPoint,我想使用setValue的原因是因为这是一个抽象类,所以我想保持属性setter中的实现最小化。 SetPoint仅仅是一个例子,在派生类中定义了更多的道具,这些道具应该以相同的方式处理。 – djv 2014-09-04 20:38:47

回答

3

我能想到的最好的解决方案将涉及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); 
+0

我曾考虑过使用反射,但表达式并没有发生在我身上。我会试试看。 – djv 2014-09-04 21:14:23