2014-09-04 5 views
2

일부 조건이 충족 될 때만 매개 변수의 후행 필드 설정을 연기 할 수있는 메커니즘을 찾고 있습니다. 람다 식에서 ref 매개 변수를 사용해야하기 때문에 걸쇠가 튀어 나올 때까지 디자인을 생각했습니다. 람다에 ref 매개 변수를 넣지 않아도이 작업을 수행 할 수 있습니까? 내가 생각할 수있는나중에 속성 값을 설정하는 방법

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' 액션 람다를 사용할 수 있습니까? –

+0

안에는 setValue()가 없기 때문에 _setPoint에만 해당되며 setValue를 사용하려는 이유는 추상 클래스이므로 속성을 최소한으로 유지하려는 것입니다. SetPoint는 단지 예일 뿐이므로 동일한 방식으로 처리해야하는 파생 클래스에 더 많은 소품이 정의됩니다. – djv

답변

3

가장 좋은 해결책은 Expression을 포함한다. 속성 보유 개체, 속성 정보 및 설정할 값을 저장 한 다음 준비가되었을 때 설정하는 것이 좋습니다.

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>>(); 
내가 쓴 다른 answer에서 조금 이겠지

, 당신은 표현에서 PropertyInfo를 얻을 수있는 기능을 가질 수있다

그런 다음 필요에 따라 해당 목록에 추가하십시오.

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

관련 문제