2010-04-05 7 views
3

내가 꺼져 있거나 완전히 닫혀있을 수 있습니다. 어느 쪽이든, 저는 현재 SOL입니다. :)C# 스레드 안전 확장 메서드

클래스의 속성을 설정하기 위해 확장 메서드를 사용할 수 있지만 해당 클래스가 비 UI 스레드에서 업데이트되거나 업데이트되지 않도록 할 수 있고 업데이트를 적용하는 클래스에서 파생됩니다. UI 스레드 (INotifyPropertyChanged 등을 구현)에 있어야합니다. 나는이 같은 확장 메서드 클래스 정의 뭔가가

public class ClassToUpdate : UIObservableItem 
{ 
    private readonly Dispatcher mDispatcher = Dispatcher.CurrentDispatcher; 
    private Boolean mPropertyToUpdate = false; 

    public ClassToUpdate() : base() 
    { 
    } 

    public Dispatcher Dispatcher 
    { 
     get { return mDispatcher; } 
    } 

    public Boolean PropertyToUpdate 
    { 
     get { return mPropertyToUpdate; } 
     set { SetValue("PropertyToUpdate", ref mPropertyToUpdate, value; } 
    } 
} 

:

나는이 같은 클래스 정의 뭔가를 분명히

static class ExtensionMethods 
{ 
    public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList, 
                Boolean newValue) 
    { 
     ClassToUpdate firstClass = sourceList.FirstOrDefault() as ClassToUpdate; 

     if (firstClass.Dispatcher.Thread.ManagedThreadId != 
      System.Threading.Thread.CurrentThread.ManagedThreadId) 
     { 
      // WHAT GOES HERE? 
     } 
     else 
     { 
      foreach (var classToUpdate in sourceList) 
      { 
       (classToUpdate as ClassToUpdate).PropertyToUpdate = newValue; 
       yield return classToUpdate; 
      } 
     } 
    } 
} 

을, 나는이 "무엇을 간다 찾고 있어요 "확장 메소드에서.

감사합니다, WTS

+1

당신은 'SetMyProperty'라는 열거 있나요? 어쩌면이 함수가 실제로 무엇을해야 하는지를 먼저 결정해야합니다. –

+0

@Henk : 실제로, 나는 유창한 API라고 생각한다 :'sourceList.SetMyProperty (true) .SetMyOtherProperty ("hello"). SetFoo (42) ...' –

+0

확장 메소드는 정적 메소드보다 아무것도 알 수 없다. '장식'하는 값 (이 작업은 컴파일 타임에 전체적으로 수행됩니다). 스레드 안전은 스레드가 수행하는 작업과 관련하여 어떤 상황에서 발생 하는지를 나타냅니다. 그러나, 그렇지 않으면 그들에 관하여 특별한 것이 없습니다. 스레딩. 일반적으로 SynchronizationContext와 디스패처를 사용하고 싶습니다. –

답변

1

가 // 무엇을 간다? 현재 스레드가 UI에 액세스 할 수 있는지 여부를 확인해야하는 경우

mDispatcher.Invoke(new Action(() => sourceList.SetMyProperty(newValue))); 

측면 참고로, 당신은 스레드 ID를 비교 할 필요가 없습니다.


UPDATE

OK, 내 대답은 '년후 이유는 ...이 방법은 인텔리에 숨겨진 몇 가지 이유

if (firstClass.Dispatcher.CheckAccess()) 
{ 
    ... 
} 

아무 생각 : 당신은 단지 CheckAccess 메서드를 호출 할 필요가 없습니다 완전히 정확한 ... 아직 yield return 컬렉션의 각 항목이 필요하고 Invoke가 수행하지 않습니다. 여기에 귀하의 방법의 또 다른 버전입니다 : 내가 제네릭 형식 매개 변수에 constaint을 추가

public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList, bool newValue) 
    where T : ClassToUpdate 
{ 
    Action<T> setProperty = t => t.PropertyToUpdate = newValue; 

    foreach(var t in sourceList) 
    { 
     if (t.Dispatcher.CheckAccess()) 
     { 
      action(t); 
     } 
     else 
     { 
      t.Dispatcher.Invoke(action, new object[] { t }); 
     } 
    } 
} 

주, 나는 (당신이 그 일을 한 방법은, 제네릭은 어떤 혜택을 가져 오지 않았다)

+0

이것이 작동하는지 잘 모르겠습니다. 어떤 이유로 Invoke를 호출 한 후 중단 점과 추적 점에 함수가 적용되지 않습니다. Invoke가 호출 된 후 함수의 첫 번째 줄에서 중단 점에 도달 할 것으로 예상됩니다. –

+0

또한 Invoke는 yield return을 통해 IEnumerable을 만드는 다른 루프와 동일한 효과를 줍니까? Invoke로부터 반환 된 객체는 null입니다. –

+0

업데이트 된 답변보기 –

0
캐스트를 제거

위의 예에서 몇 가지 작은 오타를 정리하고 (내 자신을 추가하지 않기를 바랍니다) 여기에 예제에 대한 최종 해결책이 있습니다.

public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList, 
    bool newValue) where T : ClassToUpdate 
{ 
    Action<T> setProperty = t => t.PropertyToUpdate = newValue; 

    foreach(var t in sourceList) 
    { 
     if (t.Dispatcher.CheckAccess()) 
     { 
      setProperty(t); 
     } 
     else 
     { 
      t.Dispatcher.Invoke(setProperty, new object[] { t }); 
     } 

     yield return t; 
    } 
}