2014-09-04 106 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